揭秘-的暗藏技艺-AOP-从概念到实用场景-Spring (神秘丂丂是什么意思)
环境:Spring5.3.23
1.引见
当天看Spring文档看到这么一个常识点《ControlFlowPointcuts》都不好翻译
官网原文:
SpringcontrolflowpointcutsareconceptuallysimilartoAspectJcflowpointcuts,althoughlesspowerful.(Thereiscurrentlynowaytospecifythatapointcutrunsbelowajoinpointmatchedbyanotherpointcut.)Acontrolflowpointcutmatchesthecurrentcallstack.Forexample,itmightfireifthejoinpointwasinvokedbyamethodinthecom.mycompany.webpackageorbytheSomeCallerclass.Controlflowpointcutsarespecifiedbyusingtheorg.springframework.aop.support.ControlFlowPointcutclass.
大意:Spring控制流切入点在概念上相似于aspectjcflow切入点,虽然性能不那么弱小。(目前还没有方法指定一个切入点在与另一个切入点婚配的衔接点上方运转。)控制流切入点与以后调用堆栈婚配。例如,假设衔接点由com.mycompany.web包中的方法或someecaller类调用,则或许会触发该衔接点。控制流切入点是经过经常使用org.springframework.aop.support.ControlFlowPointcut类指定的。
其实看完这个,或许你还是疑问什么意思,接上去咱们来跑一个实例,就能明确撒意思了。
2.ControlFlow实例
预备几个方法嵌套调用的类
staticclassPersonDAO{publicvoidsave(Stringname){System.out.println("PersonDAOsavemethodinvoke...");}}staticclassPersonService{privatePersonDAOdao;publicPersonService(PersonDAOdao){this.dao=dao;}publicvoidsave(Stringname){System.out.println("PersonServicesavemethodinovke...");this.dao.save(name);}}staticclassPersonManager{privatePersonServiceps;publicvoidsetPs(PersonServiceps){this.ps=ps;}publicvoidindex(Stringname){System.out.println("PersonManagerindexmethodinvoke...");this.ps.save(name);}}
上方的类及方法调用十分繁难:PersonManager--->PersonService--->PersonDAO。接上去是经过编程的形式创立PersonService代理对象。
//实例化上方的类PersonDAOdao=newPersonDAO();PersonServicetarget=newPersonService(dao);PersonManagerpm=newPersonManager();Class<?>clazz=PersonManager.class;StringmethodName="index";//定义切入点ControlFlowPointcutpointcut=newControlFlowPointcut(clazz,methodName);//定义通知MethodInterceptorlogInterceptor=invocation->{System.out.println("beforelog...");Objectret=invocation.proceed();System.out.println("afterlog...");returnret;};//定义切面DefaultPointcutAdvisoradvisor=newDefaultPointcutAdvisor(pointcut,logInterceptor);//经过ProxyFactory创立代理对象,创立的是PersonService对象的代理ProxyFactoryfactory=newProxyFactory(target);factory.addAdvisor(advisor);//基于CGLIB生成代理factory.setProxyTargetClass(true);PersonServiceps=(PersonService)factory.getProxy();pm.setPs(ps);pm.index("张三");
控制台输入
PersonManagerindexmethodinvoke...beforelog...PersonServicesavemethodinovke...PersonDAOsavemethodinvoke...afterlog...
从输入的结果发现,在PersonService#save方法之前之前和之后区分打印了日志信息。原理是什么呢?这里咱们须要先看ControlFlowPointcut切入点是如何上班的。
ControlFlowPointcut外围方法
这里只列出了几个关键的方法,在spring中只支持方法级别的阻拦。
publicclassControlFlowPointcutimplementsPointcut,ClassFilter,MethodMatcher,Serializable{privatefinalClass<?>clazz;@NullableprivatefinalStringmethodName;//对应类级别的婚配所有前往true,就是都婚配@Overridepublicbooleanmatches(Class<?>clazz){returntrue;}//方法婚配,间接true@Overridepublicbooleanmatches(Methodmethod,Class<?>targetClass){returntrue;}//这里是关键,只要isRuntime前往了true才有或许调用上方3个参数的matches方法@OverridepublicbooleanisRuntime(){returntrue;}//该方法的调用须要上方2个参数的matches方法前往true且isRuntime方法也前往true才会调用这里@Overridepublicbooleanmatches(Methodmethod,Class<?>targetClass,Object...args){//遍历以后线程的口头栈状况(也就是以前方法的调用栈状况)for(StackTraceElementelement:newThrowable().getStackTrace()){//这里就开局判别以后口头的类能否与给定的类相反&&以后设置的methodName为空或许以后栈口头的方法名与给定的方法名相反if(element.getClassName().equals(this.clazz.getName())&&(this.methodName==null||element.getMethodName().equals(this.methodName))){//最终这里只要前往了true,咱们上方的通知MethodInterceptor才会被口头returntrue;}}returnfalse;}}
有了上方源码的剖析后,咱们再来看看上方的示例代码:
//指明要婚配的类Class<?>clazz=PersonManager.class;//指明要婚配的方法名StringmethodName="index";/***将传入到切入点中;而在该切入点的matches方法中启动了判别,*整个口头的线程栈中的一切类及方法能否与这里给定的相反,*只要相反了阻拦器才干口头*/ControlFlowPointcutpointcut=newControlFlowPointcut(clazz,methodName);
剖析到这你应该知道这个ControlFlow有撒用了吧,总结:
ControlFlow就是用来判别以后口头的线程栈中(一切方法的调用)能否与你给定的类及方法婚配,只要婚配了才干口头咱们的增强(通知)代码。
繁难说:我PersonService想监控PersonManager中的index方法能否调用了我。
官网有这段说明:
Dynamicpointcutsarecostliertoevaluatethanstaticpointcuts.Theytakeintoaccountmethodargumentsaswellasstaticinformation.Thismeansthattheymustbeevaluatedwitheverymethodinvocationandthattheresultcannotbecached,asargumentswillvary.
Themnexampleisthe
controlflow
pointcut.
大意:与静态快捷形式相比,灵活快捷形式的评价老本更高。它们会思考方法参数和静态信息。这象征着每次调用方法时都肯定对其启动评价,而且因为参数会出现变动,因此不可缓存评价结果。控制流快捷形式就是一个关键的例子。
3.ControlFlow性能
雷同来自官网说明:
Controlflowpointcutsaresignificantlymoreexpensivetoevaluateatruntimethanevenotherdynamicpointcuts.In1.4,thecostisaboutfivetimesthatofotherdynamicpointcuts.
大意:与其余灵活切入点相比,控制流切入点在运转时评价的老本要高得多。在Java1.4中,老本大概是其余灵活切入点的五倍。
spring aop可以做哪些业务
事务、日志、分布式锁。 1、在软件业springaop可以使用的应用场景有事务,在标注Transactional注解的方法上,可以实现自动开启、提交、回滚事务。 2、日志,记录方法执行前的入参和执行后的结果。 3、分布式锁,由于大型软件架构都是分布式服务,当需要实现分布式锁时,可以利用AOP和自定义注解的方式,在Service执行前上锁,执行结束后解锁。
springaop可以实现哪些类型的通知
Spring AOP可以实现前置通知(Before Advice)、后置通知(After Advice)、返回通知(After Returning Advice)、异常通知(After Throwing Advice)和环绕通知(Around Advice)。 1. 前置通知(Before Advice):在某方法调用前执行的通知。 此通知无法阻止方法的执行。 例如,我们可以在方法执行前记录日志,或者进行权限验证。 代码示例如下:java@Before(execution( ..(..)))public void logBefore(JoinPoint joinPoint) {(Before method: + ());}2. 后置通知(After Advice):在某方法调用后执行的通知,无论方法是否成功。 例如,我们可以用它在方法执行后做一些清理工作。 代码示例如下:java@After(execution( ..(..)))public void logAfter(JoinPoint joinPoint) {(After method: + ());}3. 返回通知(After Returning Advice):在某方法成功返回后执行的通知。 它可以访问到方法的返回值。 例如,我们可以使用它在方法成功返回后,记录一些信息。 代码示例如下:java@AfterReturning(pointcut = execution( ..(..)), returning = retVal)public void logAfterReturning(JoinPoint joinPoint, Object retVal) {(After returning method: + () + , return value: + retVal);}4. 异常通知(After Throwing Advice):在某方法抛出异常后执行的通知。 它可以访问到抛出的异常。 例如,我们可以用它来记录异常信息。 代码示例如下:java@AfterThrowing(pointcut = execution( ..(..)), throwing = ex)public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {(After throwing method: + () + , exception: + ex);}5. 环绕通知(Around Advice):包围某方法的调用,可以在方法调用前后执行自定义的行为。 它是最强大的通知类型,因为它可以控制何时执行方法,甚至可以完全阻止方法的执行。 代码示例如下:java@Around(execution( ..(..)))public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {(Around before method: + ());Object result = (); // 执行方法(Around after method: + ());return result;}以上五种类型的通知,基本上覆盖了方法调用的所有可能场景,使得Spring AOP具有相当高的灵活性和实用性。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。