设计模式 - 代理模式
发布时间:2026/10/24 1:40:06 锦皓数字建站

代理模式概述代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。代理类似中介的身份应用场景安全代理屏蔽对真实角色的直接访问。远程代理通过代理类处理远程方法调用RMI延迟加载先加载轻量级的代理对象真正需要再加载真实对象比如你要开发一个大文档查看软件大文档中有大的图片有可能一个图片有 100MB在打开文件时不可能将所有的图片都显示出来这样就可以使用代理模式当需要查看图片时用proxy来进行大图片的打开。分类静态代理静态定义代理类专门针对某个接口动态代理动态生成代理类不显式的写代理类JDK自带的动态代理需要反射等知识一、静态代理模式学习地址https://www.bilibili.com/video/BV1Kb411W75N/?p355spm_id_from333.1007.top_right_bar_window_history.content.clickvd_source461545ff50a35eaeaa8218ecdc5f7152实现步骤1、创建一个类NetWorkTest2、创建一个接口NetWork其中有browse()方法需要被代理类和被代理类共同实现3、创建被代理类Server实现NetWork接口重写其中的browse()方法4、创建代理类ProxyServer实现NetWork接口。声明变量NetWork、提供代理类ProxyServer构造器、重写的browse()方法调用NetWork.browse()5、使用时new一个真实的被代理类server、new一个代理类ProxyServer传入server、调用ProxyServer的browse()方法不直接使用server.browse()的好处就是不止可以调用server.browse()方法proxyServer.browse()中还能做些其它的事比如信息校验等//1、创建一个类NetWorkTestpublicclassNetWorkTest{publicstaticvoidmain(String[]args){//new一个真实的被代理类serverServerservernewServer();//server.browse();//相当于server赋予了ProxyServer中的NetWork//因为server和ProxyServer都实现了NetWork所以server可以当作NetWork传入构造器ProxyServer(NetWork work)实际调用的是实现NetWork 的server.browse()ProxyServerproxyServernewProxyServer(server);proxyServer.browse();}}//代理类和被代理类共同实现的接口NetWorkinterfaceNetWork{publicvoidbrowse();//浏览的方法}//被代理类classServerimplementsNetWork{Overridepublicvoidbrowse(){System.out.println(真实的服务器访问网络);}}//代理类classProxyServerimplementsNetWork{//声明变量privateNetWorkwork;//提供当前代理类的构造器publicProxyServer(NetWorkwork){this.workwork;//对work进行初始化}//校验的方法publicvoidcheck(){System.out.println(联网之前的检查工作);}Overridepublicvoidbrowse(){check();//先调用check方法校验work.browse();//真实的情况下使用work进行browse操作}}二、动态代理模式学习地址https://www.bilibili.com/video/BV1Vf4y127N5?p25vd_source461545ff50a35eaeaa8218ecdc5f7152动态代理主要是Spring的两大特点之一AOP即面向切面编程AOP为Aspect Oriented Programming的缩写意为面向切面编程通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性同时提高了开发的效率。什么是 AOP1、通俗描述不通过修改源代码方式在主干功能里面添加新功能2、通常使用AspectJ框架实现AOP主要意图将日志记录性能统计安全控制事务处理异常处理等代码从业务逻辑中划分出来通过对这些行为的分离我们希望可以将他们独立到非指导业务逻辑的方法中进而改变这些行为的时候不影响业务逻辑的代码。使用登录例子说明 AOP:普通的登录功能添加权限控制时需要修改原代码。创建新的权限判断模块通过AOP加到原有的登录流程中可以不改变原代码1、AOP 使用动态代理的两种情况代理创建被增强对象的代理对象通过代理对象将功能做到第一种 有接口情况使用 JDK 动态代理创建接口实现类UserDaoImpl代理对象增强类的方法第二种 没有接口情况使用 CGLIB 动态代理创建子类Person的代理对象增强类的方法2、底层原理JDK动态代理实现基本逻辑1、创建接口UserDao2、创建接口的实现类UserDaoImpl3、创建代理对象UserDaoProxy实现InvocationHandler接口里面写增强的方法4、调用Proxy.newProxyInstance传入类加载器实现的接口UserDao实现InvocationHandler这个接口的类UserDaoProxy1.创建接口定义方法创建接口UserDaopublicinterfaceUserDao{publicintadd(inta,intb);//相加方法publicStringupdate(Stringid);//直接返回方法}2.创建接口实现类实现方法创建实现类UserDaoImpl 实现UserDao接口publicclassUserDaoImplimplementsUserDao{Overridepublicintadd(inta,intb){//相加方法returnab;}OverridepublicStringupdate(Stringid){//直接返回方法returnid;}}3.创建增强类实现InvocationHandler接口创建增强类UserDaoProxy 实现InvocationHandler接口里面编写增强的内容//创建代理对象代码里面写增强的逻辑实现InvocationHandler接口classUserDaoProxyimplementsInvocationHandler{//1 把创建的是谁的代理对象把谁传递过来//UserDaoImpl//有参数构造传递new UserDaoProxy(userDao)传递对象privateObjectobj;publicUserDaoProxy(Objectobj){this.objobj;}//invoke里面写增强的逻辑//三个参数proxy就是代理对象newProxyInstance方法的返回对象method调用的方法args: 方法中的参数OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//方法之前System.out.println(方法之前执行....method.getName() :传递的参数...Arrays.toString(args));//被增强的方法执行Objectresmethod.invoke(obj,args);//方法之后System.out.println(方法之后执行....obj);returnres;}}4.使用 Proxy 类创建接口代理对象调用方法newProxyInstance 方法有三个参数第一参数类加载器第二参数增强方法所在的类这个类实现的接口UserDao 支持多个接口第三参数实现InvocationHandler这个接口创建代理对象写增强的部分importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.EnableAspectJAutoProxy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.util.Arrays;publicclassJDKProxy{publicstaticvoidmain(String[]args){Class[]interfaces{UserDao.class};UserDaoImpluserDaonewUserDaoImpl();//创建的代理对象传到new UserDaoProxy(userDao)里//创建接口实现类代理对象//Proxy.newProxyInstance类加载器实现的接口实现InvocationHandler这个接口的类UserDaodao(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,newUserDaoProxy(userDao));intresultdao.add(1,2);System.out.println(result:result);}}3、AspectJ操作术语连接点类里面哪些方法可以被增强称为连接点切入点实际被真正增强的方法通知增强实际增强的逻辑部分称为通知增强通知有多种类型前置通知增强的方法前面执行后置通知增强的方法后面执行环绕通知增强的方法前后都有执行异常通知出现异常执行最终通知类似finally切面是动作把通知应用到切入点的过程。例如将权限判断加入到登录方法的过程Aspect切面 Aspect 声明类似于 Java 中的类声明在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。Joint point连接点表示在程序中明确定义的点典型的包括方法调用对类成员的访问以及异常处理程序块的执行等等它自身还可以嵌套其它 joint point。Pointcut切点表示一组 joint point这些 joint point 或是通过逻辑关系组合起来或是通过通配、正则表达式等方式集中起来它定义了相应的 Advice 将要发生的地方。Advice增强Advice 定义了在Pointcut里面定义的程序点具体要做的操作它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。Target目标对象织入Advice的目标对象.。Weaving织入将Aspect和其他对象连接起来, 并创建Adviced object的过程4、AspectJ准备工作1、Spring 框架一般都是基于 AspectJ 实现 AOP 操作AspectJ 不是 Spring 组成部分AspectJ 不需要Spring 也能独立使用独立 AOP 框架一般把 AspectJ 和 Spirng 框架一起使用进行 AOP 操作2、基于 AspectJ 实现 AOP 操作两种主要方式1.基于 xml 配置文件实现2.基于注解方式实现一般使用方式3、在项目工程里面引入 AOP 相关依赖4、切入点表达式1切入点表达式作用知道对哪个类里面的哪个方法进行增强2语法结构 execution([权限修饰符] [返回类型] [类全路径] 方法名称 )//*表示任意的修饰符返回类型可以省略不写参数列表..表示//举例 1对 com.atguigu.dao.BookDao 类里面的 add 进行增强execution(*com.atguigu.dao.BookDao.add(..))//举例 2对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强execution(*com.atguigu.dao.BookDao.*(..))//举例 3对 com.atguigu.dao 包里面所有类类里面所有方法进行增强execution(*com.atguigu.dao.*.*(..))5、相同的切入点抽取切入点表达式相同时可以抽取出来在方法上面加入切入点注解Pointcut之后使用时只需要使用方法//相同切入点抽取Pointcut(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidpointdemo(){}//前置通知//Before 注解表示作为前置通知Before(valuepointdemo())publicvoidbefore(){System.out.println(before.........);}5、AspectJ注解开发-重点1.编写配置文件创建配置类可以不需要xml 配置文件都用注解做到ConfigurationComponentScan(basePackages{com.atguigu})//开启注解扫描EnableAspectJAutoProxy(proxyTargetClasstrue)//开启 Aspect 生成代理对象publicclassConfigAop{}2.创建被增强类在类里面定义方法//被增强类ComponentpublicclassUser{publicvoidadd(){System.out.println(add.......);}}3.创建增强类配置不同类型的通知编写增强的逻辑在增强类的里面在作为通知方法上面添加通知类型注解使用切入点表达式配置importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;//增强的类ComponentAspect//生成代理对象Order(3)//有多个增强类多同一个方法进行增强设置增强类优先级Order(数字类型值)数字类型值越小优先级越高两个增强类都会执行publicclassUserProxy{//相同切入点抽取Pointcut(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidpointdemo(){}//前置通知//Before注解表示作为前置通知Before(valuepointdemo())publicvoidbefore(){System.out.println(before.........);}//后置通知返回通知AfterReturning(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidafterReturning(){System.out.println(afterReturning.........);}//最终通知After(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidafter(){System.out.println(after.........);}//异常通知AfterThrowing(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidafterThrowing(){System.out.println(afterThrowing.........);}//环绕通知Around(valueexecution(* com.atguigu.spring5.aopanno.User.add(..)))publicvoidaround(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println(环绕之前.........);//被增强的方法执行proceedingJoinPoint.proceed();System.out.println(环绕之后.........);}}4.配置xml文件方式-了解可以作为配置类方式的替代仅供参考使用比较麻烦在 spring 配置文件中开启注解扫描需要新加xmlns:contextxmlns:aop xsi:schemaLocation?xml version1.0 encodingUTF-8?beansxmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd!-- 开启注解扫描 --context:component-scanbasepackagecom.atguigu.spring5.aopanno/context:component-scan!-- 开启 Aspect 生成代理对象--!-- 到类上面寻找Aspect注解有注解生成代理对象--aop:aspectj-autoproxy/aop:aspectj-autoproxy6、AspectJ 配置文件开发-了解1、创建两个类增强类和被增强类创建方法packagecom.atguigu.spring5.aopxml;publicclassBook{publicvoidbuy(){System.out.println(buy.............);}}packagecom.atguigu.spring5.aopxml;publicclassBookProxy{publicvoidbefore(){System.out.println(before.........);}}2、在 spring 配置文件中创建两个类对象!--创建对象--beanidbookclasscom.atguigu.spring5.aopxml.Book/beanbeanidbookProxyclasscom.atguigu.spring5.aopxml.BookProxy/bean3、在 spring 配置文件中配置切入点!--配置 aop 增强--aop:config!--切入点id起个名字--aop:pointcutidpexpressionexecution(* com.atguigu.spring5.aopxml.Book.buy(..))/!--配置切面--aop:aspectrefbookProxy!--增强作用在具体的方法上--aop:beforemethodbeforepointcut-refp//aop:aspect/aop:config
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。