【基础原理】java代理模式和Spring AOP的基本逻辑

发布时间:2026/11/3 18:16:42
【基础原理】java代理模式和Spring AOP的基本逻辑 先通过了解代理模式的原理 希望知道动态代理是怎么实现的动态增强然后再具体看下spring AOP是如何使用动态代理实现的切面、织入等逻辑。文章目录一. 代理模式1. 代理的概念2. 静态代理3. 动态代理3.1. 概述3.2. 代码实现3.3. 源码理解二. Spring AOP中的代理原理1. 一个简单的场景2. AOP概念分析3. 实操一. 代理模式1. 代理的概念代理模式是指client调用一个对象时通过代理实例调用并增强此对象而不是直接调用它。2. 静态代理看下静态代理的实现思路为理解动态代理提供一些基础实现的基本思路通过实现同一个接口用于实现方法增强 接口聚合到代理类中。如下代码//代理和被代理对象都要实现的接口publicinterfaceITeacherDao{voidteach();// 授课的方法}//被代理对象publicclassTeacherDaoimplementsITeacherDao{Overridepublicvoidteach(){System.out.println( 老师授课中 。。。。。);}}//静态代理对象publicclassTeacherDaoProxyimplementsITeacherDao{privateITeacherDaotarget;//聚合被代理对象publicTeacherDaoProxy(ITeacherDaotarget){//面向接口编程this.targettarget;}Overridepublicvoidteach(){System.out.println(开始代理 完成某些操作。。。。。 );//增强target.teach();//被代理对象的方法System.out.println(提交。。。。。);//增强}}//client将被代理类放入到代理类然后通过创建代理类来调用被代理对象的方法。TeacherDaoteacherDaonewTeacherDao();TeacherDaoProxyteacherDaoProxynewTeacherDaoProxy(teacherDao);teacherDaoProxy.teach();小结实现逻辑其实不难就是代理class、被代理class都实现一个接口且代理class的方法实现了被代理对象的增强。这里的增强需要注意使用了面向接口编程即可以根据被代理class的不同调用不同的被代理instance的方法增强在执行时会在被执行方法前后进行添加一些执行逻辑。上面的逻辑其实解释了代理的基本要素被代理对象的方法是代理对象去调用而不是自己调用因为调用被代理所以可以在被调用前后进行增强。但静态代理的缺点也比较明显每个被代理类都需要手动去实现代理类如果需要代理的类比较多那代码是比较臃肿的。3. 动态代理3.1. 概述动态代理的代理类并不是在Java代码中定义的而是在JVM运行时根据我们在Java代码中的“指示”动态生成的。所以相比于静态代理动态代理可以统一处理被代理类的所有方法而不用修改每个代理类的方法。3.2. 代码实现//接口publicinterfaceITeacherDao{voidteach();voidsayHello(Stringname);}//目标类被代理类publicclassTeacherDaoimplementsITeacherDao{Overridepublicvoidteach(){System.out.println( 老师授课中.... );}OverridepublicvoidsayHello(Stringname){System.out.println(hello name);}}//代理工厂publicclassProxyFactory{privateObjecttarget;publicProxyFactory(Objecttarget){this.targettarget;}//给目标对象 生成一个代理对象publicObjectgetProxyInstance(){returnProxy.newProxyInstance(target.getClass().getClassLoader(),//1. 类加载器创建代理类时检查target.getClass().getInterfaces(),//2. 接口创建代理类要素1newInvocationHandler(){//3. 代理逻辑创建代理类要素2OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println(JDK代理开始~~);ObjectreturnValmethod.invoke(target,args);System.out.println(JDK代理提交);returnreturnVal;}});}}ITeacherDaotargetnewTeacherDao();ITeacherDaoproxyInstance(ITeacherDao)newProxyFactory(target).getProxyInstance();proxyInstance.teach();proxyInstance.sayHello( tom );这里我们可以将invocationHandler看作是一个代理类携带着被代理对象在invoke方法中调用了被代理对象的方法并可以在方法前后进行增强。3.3. 源码理解动态构建动态代理类的逻辑我们利用Proxy类的newProxyInstance方法创建了一个动态代理对象看下源码具体是怎么实现的//java.lang.reflect.ProxyCallerSensitivepublicstaticObjectnewProxyInstance(ClassLoaderloader,Class?[]interfaces,InvocationHandlerh)throwsIllegalArgumentException{...一些检查和校验finalClass?[]intfsinterfaces.clone();//生成代理类通过类加载器 代理接口Class?clgetProxyClass0(loader,intfs);/* * Invoke its constructor with the designated invocation handler. */try{...一些检查和校验finalConstructor?conscl.getConstructor(constructorParams);finalInvocationHandlerihh;if(!Modifier.isPublic(cl.getModifiers())){AccessController.doPrivileged(newPrivilegedActionVoid(){publicVoidrun(){cons.setAccessible(true);returnnull;}});}//通过反射构造出来的构造器实现了动态代理对象returncons.newInstance(newObject[]{h});}catch。。。}源码的基本逻辑先通过Class? cl getProxyClass0(loader, intfs)获取到了代理class实例然后通过类实例创建了构建器进而实现了代理对象。执行getProxyClass0方法时会动态的生成一个代理类文件下面我们看一下类文件的具体内容//动态生成的代理类文件//0表示生成的第一个代理类如果有多个序号会依次递增publicfinalclass$Proxy0extendsProxyimplementsPerson{privatestaticMethodm1;privatestaticMethodm2;privatestaticMethodm3;privatestaticMethodm0;/** *这里是代理类的构造器注意看入参数类型是InvocationHandler * *super(paramInvocationHandler)是调用父类Proxy的构造方法。 *父类持有protected InvocationHandler h; *Proxy构造方法 * protected Proxy(InvocationHandler h) { * Objects.requireNonNull(h); * this.h h; * } */public$Proxy0(InvocationHandlerparamInvocationHandler)throws{super(paramInvocationHandler);}static{try{//注意看giveMoney通过反射得到方法名字是m3m1Class.forName(java.lang.Object).getMethod(equals,newClass[]{Class.forName(java.lang.Object)});m2Class.forName(java.lang.Object).getMethod(toString,newClass[0]);m3Class.forName(proxy.Person).getMethod(giveMoney,newClass[0]);m0Class.forName(java.lang.Object).getMethod(hashCode,newClass[0]);return;}catch...}/** *直接就调用了InvocationHandler中的invoke方法并把m3传了进去这里的m3其实就是被代理方法 *看到这里大概知道了动态代理的本质是通过InvocationHandler去调用被代理类的方法 */publicfinalvoidgiveMoney()throws{try{this.h.invoke(this,m3,null);return;}catch...}...toStringhashCode、equals方法的内容。}小结一下上面反编译的class代理类的生成首先$Proxy0是动态生成的代理类0代表第一个代理类如果有多个被代理实例序号会依次递增代理类中会生成相同签名的方法代理调用当执行方法时会找到代理类中相同签名的方法进行执行invoke执行每个代理类中都有InvocationHandler其实代理工作是他做的即他持有被代理对象通过invoke方法如上例实践增强并执行被代理实例方法。二. Spring AOP中的代理原理Spring AOP是基于代理实现的默认为标准的 JDK 动态代理。参考上述动态代理的讲解接口对象的加载器我们可以知道spring可以使得任何接口参考3.2 代理工厂或者接口的集合可以被代理。值得关注的是将被代理对象A交给代理对象B执行B执行A方法时可以在A方法执行前后进行增强但并不能改造A对象方法内部。1. 一个简单的场景有10个方法在执行前想进行一些校验校验的逻辑都一致方法执行完之后统一进行返回值的处理统一返回给某处。2. AOP概念分析先看下对于上面的场景我们需要关注那些点spring是怎么做到的指定对哪些方法进行增强切入点程序中通过切入点表达式来表示切点对这些方法怎么前、后、围绕还是异常时进行增强Advice(通知)怎么组织切点和通知通过切面。其此在程序运行过程中对于目标方法spring这边通过JointPoint连接点去表示。简单来说我们构建一个AOP逻辑先要确定切点和通知知道哪些方法要被拦截进行增强当连接点要执行时进行拦截增强而这些逻辑都被切面进行组织。3. 实操AspectComponentSlf4jpublicclassSchedulerAspect{ResourceprivateNacosServicenacosService;Pointcut(execution(* xxx.statictask.FlinkRefreshTaskDataScheduler.*(..) ) annotation(org.springframework.scheduling.annotation.Scheduled))publicvoidpointCut(){}Around(pointCut())publicObjectauditLogCut(ProceedingJoinPointjoinPoint){Objectresultnull;if(!nacosService.isApiOldestInstance()){returnresult;}try{resultjoinPoint.proceed();}catch(Throwablethrowable){log.error(throwable.getMessage());}returnresult;}}简单描述下AOP的逻辑Aspect声明了一个切面逻辑其中我们要进行增强的方法有FlinkRefreshTaskDataScheduler类下所有添加了Scheduled注解的方法通过Around下auditLogCut方法规定了增强的逻辑当方法执行前判断此进程是否时nacos注册最早的节点如果是我就允许你执行定时任务如果不是则不能执行。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询