概述工作中使用最多的是通过@Aspect实现AOP功能;在Spring配置中使用@Aspect切面,需要启用Spring支持,以便基于@Aspect切面配置SpringAOP,并根据条件自动代理bean。使用自动代理,如果Spring确定一个bean匹配一个或多个方面的建议,它会自动为该bean生成一个代理来拦截方法调用并确保建议按需运行。@AspectJ支持可以通过XML或java风格的配置启用。在这两种情况下,您还需要确保AspectJ的aspectjweaver.jar库位于应用程序的类路径(1.8或更高版本)中。通过注释启用@Aspect支持@Configuration@EnableAspectJAutoProxypublicclassAppConfig{}通过XML启用@Aspect支持。定义了AspectJ切面。packagecom.pack.aspect;importorg.aspectj.lang.annotation.Aspect;@AspectpublicclassCustomAspect{//定义切入点@Pointcut("execution(*com.pack.service..*.(..))")privatevoidlog(){}//定义通知@Before("log()")//@Before("execution(*com.pack.service..*.(..))")也可以直接完成写publicvoidrecordLogBefore(){//...}@AfterReturning("log()")publicvoidrecordLogAfter(){//...}}上面简单回顾了工作中使用@Aspect来定义切面实现AOP功能。SpringAOPAPI中的切入点Spring的切入点模型支持独立于通知类型的切入点重用。可以使用相同的切入点针对不同的建议。切入点接口是通知特定类和方法的中央接口。完整的接口如下:publicinterfacePointcut{ClassFiltergetClassFilter();MethodMatchergetMethodMatcher();}将切入点接口分成两部分允许重用类和方法匹配部分以及细粒度组合操作。ClassFilter接口用于将切入点限制为一组给定的目标类。如果matches()方法始终返回true,则匹配所有目标类。ClassFilter接口的定义如下代码清单所示:publicinterfaceClassFilter{booleanmatches(Classclazz);}这个类专门用来匹配每个Bean是否满足条件,只有匹配了才能创建代理为了它。MethodMatcher接口通常更重要。完整的接口如下:publicinterfaceMethodMatcher{/***在运行目标类的方法时,判断当前执行的方法是否匹配。如果匹配,则执行*相关通知*/booleanmatches(Methodm,Class>targetClass);/***以上2个参数的matches方法返回true执行isRuntime*该方法的返回值决定是否执行后面3个参数的matches方法*如果返回true则执行下面3个参数执行。返回false不会执行下面的方法*/booleanisRuntime();/***这个方法是否执行是由上面的isRuntime方法决定的,只有返回true才会执行*如果isRuntime方法返回true,那么Advisor*中定义的每一个A通知*(这些通知都会被转换intoMethodInterceptor)被封装为InterceptorAndDynamicMethodMatcher*最后,通过ReflectiveMethodInvocation执行时,会判断当前对象是否为ReflectiveMethodInvocation*,会进行MethodMatcher的3个参数的matches调用,参数可以对应验证判断,*是否继续调用通知,如果匹配则调用当前的MethodInterceptor,否则直接调用下一个*/booleanmatches(Methodm,Class>对入口点的操作Spring支持对入口点的操作(尤其是union和交集).Union表示一个切入点匹配的任何方法.Intersection表示两个切入点匹配的方法.联盟通常更有用。您可以使用org.springframework.aop.support.Pointcuts类中的静态方法来组合切入点,您也可以使用同一个包中的ComposablePointcut类。然而,使用AspectJ切入点表达式通常是一种更简单的方法。Union表示多个Pointcuts需要匹配才算匹配。publicabstractclassPointcuts{publicstaticPointcutunion(Pointcutpc1,Pointcutpc2){returnnewComposablePointcut(pc1).union(pc2);}}ComposablePointcutpublicclassComposablePointcutimplementsPointcut,Serializable{privateClassFilterclassFilter;私有方法匹配器方法匹配器;publicComposablePointcut(Pointcut切入点){this.classFilter=pointcut.getClassFilter();this.methodMatcher=pointcut.getMethodMatcher();}publicComposablePointcutunion(Pointcutother){this.methodMatcher=MethodMatchers.union(this.methodMatcher,this.classFilter,other.getMethodMatcher(),other.getClassFilter());this.classFilter=ClassFilters.union(this.classFilter,other.getClassFilter());归还这个;}}MethodMatchers.unionstaticMethodMatcherunion(MethodMatchermm1,ClassFiltercf1,MethodMatchermm2,ClassFiltercf2){return(mm1instanceofIntroductionAwareMethodMatcher||mm2instanceofIntroductionAwareMetho匹配器?newClassFilterAwareUnionIntroductionAwareMethodMatcher(mm1,cf1,mm2,cf2):newClassFilterAwareUnionMethodMatcher(mm1,cf1,mm2,cf2));}同上,返回ClassFilterAwareUnionMethodMatcherprivatestaticclassClassFilterAwareUnionMethodMatcherextendsUnionMethodMatcher{privatefinalClassFiltercf1;私有最终类过滤器cf2;publicClassFilterAwareUnionMethodMatcher(MethodMatchermm1,ClassFiltercf1,MethodMatchermm2,ClassFiltercf2){super(mm1,mm2);这个.cf1=cf1;这个.cf2=cf2;}}privatestaticclassUnionMethodMatcherimplementsMethodMatcher,Serializable{//最终核心是判断两个Pointcuts对应的ClassFilter,MethodMatcher//只要其中一个返回truepublicbooleanmatches(Methodmethod,Class>targetClass){return(matchesClass1(targetClass)&&this.mm1.matches(method,targetClass))||(matchesClass2(targetClass)&&this.mm2.matches(method,targetClass));}}HandypointcutimplementationSpring为我们提供了几个方便的入口点实现类,可以直接使用。静态切入点,静态切入点是基于方法和目标类的,不能考虑方法的参数。对于大多数用途,静态切入点就足够了,而且是最好的。Spring只能评估一次静态切入点,即第一次调用该方法时。之后,不需要为每个方法调用再次评估切入点。正则表达式切入点指定静态切入点的一种明显方法是使用正则表达式。除了Spring之外,还有几个AOP框架可以实现这一点。org.springframework.aop.support.JdkRegexpMethodPointcut是一个通用的正则表达式切入点,它使用JDK中的正则表达式支持。使用JdkRegexpMethodPointcut类,可以提供一组模式字符串。如果其中任何一个匹配,切入点的计算结果为真。.*set.*.*save
动态切入点的计算成本比静态切入点高。它们同时考虑了方法参数和静态信息。这意味着必须为每个方法调用计算它们,并且由于参数不同,无法缓存结果。核心入口点类:ControlFlowPointcut。公共类ControlFlowPointcut实现Pointcut、ClassFilter、MethodMatcher、Serializable{privatefinalClass>clazz;私有最终字符串方法名;/***构造一个新的切入点,匹配给定类中给定方法下的所有调用。*如果没有给出方法名,则匹配给定类下的所有控制流。*/publicControlFlowPointcut(Class>clazz,@NullableStringmethodName){this.clazz=clazz;this.methodName=方法名;}publicbooleanmatches(Methodmethod,Class>targetClass){returntrue;}@OverridepublicbooleanisRuntime(){返回真;}@Overridepublicbooleanmatches(Methodmethod,Class>targetClass,Object...args){//遍历当前执行栈中的所有方法,看是否匹配当前构造方法传入的方法名,如果有是对应的通知调用//简单的说就是:拦截创建的代理类的任意方法,如果这些方法在执行过程中调用了构造参数传入的Class和Method,那么就是Matchedfor(StackTraceElementelement:newThrowable().getStackTrace()){如果(element.getClassName().equals(this.clazz.getName())&&(this.methodName==null||element.getMethodName().equals(this.methodName))){返回真;}}返回假;}}切入点超类Spring提供了有用的切入点超类来帮助您实现自己的切入点。由于静态切入点最有用,您可能应该子类化StaticMethodMatcherPointcut。这只需要实现一个抽象方法(尽管您可以覆盖其他方法来自定义行为)。下面的例子展示了如何子类化StaticMethodMatcherPointcut: