当前位置: 首页 > 后端技术 > Java

AOP方面运行原理分析

时间:2023-04-02 00:20:11 Java

1应用日志、事务、限流、统计、上下文切换、异步等非业务逻辑处理都可以使用2例子网上随处可见,这里只是简单的例子@Aspect@ComponentpublicclassDemoAspect{@Pointcut("execution(*com.example.demo2.controller.DemoController.sayDemo())")publicvoidaa(){System.out.println("pointcut");}@Before("aa()")publicvoidbeforeDemo(JoinPointjoinPoint){System.out.println(joinPoint);System.out.println("演示前");}@After("aa()")publicvoidafterDemo(){System.out.println("演示后");}@Around("aa()")publicvoidzaroundDemo(ProceedingJoinPointjoinPoint){System.out.println("demoaround1");尝试{joinPoint.proceed();}catch(Throwablethrowable){throwable.printStackTrace();}System.out.println("demoaround2");}}3相关重要类AbstractAspectJAdviseAspectJAroundAdviceAspectJMethodBeforeAdviceAspectJAfterThrowingAdviceAspectJAfterAdviceAspectjAroundAdvice--继承自methodInterceptorAspectjMethodBeforeAdvice---还有一个MethodBeforeInterceptor用于实现动态代理4调用过程通过cglib代理生成一个代理类,重写父类的方法,在该类中添加拦截器DynamicCglibMethodInterceptor。通知(advice)对应的所有拦截器,如:AspectJMethodBeforeAdvice---MethodBeforeAdviceInterceptor;AspectJAroundAdvice的拦截器就是它自己;调用时会先遍历Advice对应的所有拦截器,调用里面的invoke方法;传递当前的CglibMethodInvocation对象;(典型的责任链模式)3.重点:AspectJAroundAdvise中有一个ProceedingJoinPoint参数,这个参数是怎么调用的?其实在Advice中,通过return调用切面类中的通知方法,method.invoke(obj,args);为了实现环绕通知?在初始化MethodInvocationProceedingJoinPoint时,也传入了CglibMethodInvocation,方便调用链的延续;如果是调用链的最后一个,那么methodInvocationProceedingJoinPoint调用完成后,直接返回周围的通知方法,然后继续向下执行,直到结束5源码分析5.1动态代理类根据System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,fileName)生成的动态代理对象;可以看到会有一个DemoController$$EnhanceByCglib对象,里面有一个callback[]数组,这个是记录的所有拦截器;通过动态生成的代理类调用demo方法时,实际过程为:publicfinalvoidsayDemo(){MethodInterceptorvar10000=this.CGLIB$CALLBACK_0;如果(var10000==null){CGLIB$BIND_CALLBACKS(this);var10000=this.CGLIB$CALLBACK_0;}#如果有拦截器,调用拦截器方法,if(var10000!=null){var10000.intercept(this,CGLIB$sayDemo$0$Method,CGLIB$emptyArgs,CGLIB$sayDemo$0$Proxy);}else{super.sayDemo();可以看到动态代理生成的类在父类的DemoController中重写了sayDemo方法,然后写了一个方法叫finalvoidCGLIB$sayDemo$0(){super.sayDemo();}调用父类的方法;拦截器的重点是什么?你怎么称呼它?5.2DynamicAdvisedInterceptor注入的拦截器,在intercept方法中,会判断advice是否为空,如果不为空,则调用retVal=newCglibMethodInvocation(proxy,target,method,args,targetClass,chain,methodProxy).proceed();5.3CglibMethodInvocation调用父类的proceed方法publicObjectproceed()throwsThrowable{//我们从索引-1开始,提前递增//如果是最后一个,则结束如果(this.currentInterceptorIndex==this.interceptorsAndDynamicMethodMatchers.size()-1){returninvokeJoinpoint();}//根据索引找到下一个通知是什么?if(interceptorOrInterceptionAdviceinstanceofInterceptorAndDynamicMethodMatcher){//在这里评估动态方法匹配器:静态部分已经//被评估并发现匹配。InterceptorAndDynamicMethodMatcherdm=(InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;类targetClass=(this.targetClass!=null?this.targetClass:this.method.getDeclaringClass());如果(dm.methodMatcher.matches(this.method,targetClass,this.arguments)){returndm.interceptor.invoke(this);}埃尔斯e{//动态匹配失败。//跳过这个拦截器并调用链中的下一个。返回继续();}}else{//它是一个拦截器,所以我们只是调用它:切入点将//在构造此对象之前被静态评估。//来到这里,调用与建议对应的MethodInterceptorreturn((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);}}假设:第一个是环绕通知对应的拦截器5.4AspectJAroundAdvicepublicObjectinvoke(MethodInvocationmi)throwsThrowable{if(!(miinstanceofProxyMethodInvocation)){thrownewIllegalStateException("MethodInvocationisnotaSpringProxyMethodInvocation:"+英里);}//将当前的CglibMethodInvocation实例对象传递给ProceedingJoinPoint,方便以后使用;ProxyMethodInvocationpmi=(ProxyMethodInvocation)mi;ProceedingJoinPointpjp=lazyGetProceedingJoinPoint(pmi);JoinPointMatchjpm=getJoinPointMatch(pmi);//使用反射调用切面中的环绕通知方法,(即上面的zaroundDemo方法)returninvokeAdviceMethod(pjp,jpm,null,null);}代码如下@Around("aa()")publicvoidzaroundDemo(ProceedingJoinPointjoinPoint){System.out.println("demoaround1");try{//这里是调用MethodInvocationProceedingJoinPoint;joinPoint.proceed();}catch(Throwablethrowable){throwable.printStackTrace();}System.out.println("demoaround2");}MethodInvocationProceedingJoinPoint.proceed方法,可以发现它实际上调用了上面作为成员变量传入的CglibMethodInvocation对象;形成调用链;publicObjectproceed()throwsThrowable{returnthis.methodInvocation.invocableClone().proceed();}5.5AspectJMethodBeforeAdvice--MethodBeforeAdviceInterceptor拦截器内部逻辑:先调用pre-advice的before方法,然后返回调用链的CglibMethodInvocation--继续责任链的调用;publicObjectinvoke(MethodInvocationmi)throwsThrowable{this.advice.before(mi.getMethod(),mi.getArguments(),mi.getThis());返回mi.proceed();}AspectJMethodBeforeAdvice.proceed也是使用反射调用切面的pre-advice;@Overridepublicvoidbefore(Methodmethod,Object[]args,@NullableObjecttarget)throwsThrowable{invokeAdviceMethod(getJoinPointMatch(),null,null);}5.6AspectJAfterAdvice是finally中反射调用中编织的post-advice;publicObjectinvoke(MethodInvocationmi)throwsThrowable{try{returnmi.proceed();}最后{invokeAdviceMethod(getJoinPointMatch(),null,null);}}5.7责任链的最后一步:--invokeJoinpointif(this.currentInterceptorIndex==this.interceptorsAndDynamicMethodMatchers.size()-1){returninvokeJoinpoint();}invokeJoinPointprotectedObjectinvokeJoinpoint()throwsThrowable{//如果通过cglib代理,调用动态代理方法if(this.methodProxy!=null){try{returnthis.methodProxy.invoke(this.target,this.arguments);}catch(CodeGenerationExceptionex){logFastClassGenerationFailure(this.method);}}//否则,通过反射调用返回super.invokeJoinpoint();通知放在列表中,采用责任链模式逐一调用;最后触发cglib的动态代理,调用MethodProxy.invoke方法

最新推荐
猜你喜欢