文章导航
目录
文章导航
前言
正文
方法1:getInterceptorsAndDynamicInterceptionAdvice
方法2:getInterceptorsAndDynamicInterceptionAdvice
方法3:getInterceptors
方法4:proceed
AOP的几种增强方法
切面配置方式
实现MethodInterceptor接口
实现AdvisorAdapter子接口
总结
前言
前面的章节讲解了AOP的配置文件解析过程,及其代理文件的生成过程,AOP生成代理的方式有Cglib和JDK动态代理两种方法,根据配置及其接口实现情况,挑选出代理方法。生成代理类后,调用其具体方法时,会调用其所配置的切面方法,其使用的是责任链设计模式,本篇文章会讲解其解析过程。
正文
public static void main(String[] args) { //指定代理文件生成位置 //JDK System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\Code\\SourceCode\\LeanCode\\Spring\\spring-framework-zh\\com"); //CGLIB System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("application-aop.xml"); MyAccount myAccount = (MyAccount) applicationContext.getBean("myAccount"); myAccount.transfer(); }
我们从调用代理类的方法作为入口,这里以Cglib动态代理方式为例。在调用myAccount.transfer()方法时,会调用其回调方法。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; //获取目标类类型,TargetSource 是其封装类 TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = targetSource.getTarget(); //获取被代理类类型 Class<?> targetClass = (target != null ? target.getClass() : null); // 从advised中获取配置好的AOP通知 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. // 如果没有aop通知配置,那么直接调用target对象的调用方法 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // We can skip creating a MethodInvocation: just invoke the target directly. // Note that the final invoker must be an InvokerInterceptor, so we know // it does nothing but a reflective operation on the target, and no hot // swapping or fancy proxying. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 如果拦截器链为空则直接激活原方法 retVal = methodProxy.invoke(target, argsToUse); } else { // We need to create a method invocation... // 通过cglibMethodInvocation来启动advice通知 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass),见方法1详解
new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(),见方法4详解
方法1:getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { // 创建一个method的缓存对象,在MethodCacheKey中实现了equals和hashcode方法同时还实现了compareTo方法 MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); // 先从缓存中获取,如果缓存中获取不到,则再调用方法获取,获取之后放入到缓存中 if (cached == null) { // 调用的是advisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice方法 cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass),见方法2详解
方法2:getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. // 这里用了一个单例模式 获取DefaultAdvisorAdapterRegistry实例 // 在Spring中把每一个功能都分的很细,每个功能都会有相应的类去处理 符合单一职责原则的地方很多 这也是值得我们借鉴的一个地方 // AdvisorAdapterRegistry这个类的主要作用是将Advice适配为Advisor 将Advisor适配为对应的MethodInterceptor AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); // 创建一个初始大小为 之前获取到的 通知个数的集合 List<Object> interceptorList = new ArrayList<>(advisors.length); // 如果目标类为null的话,则从方法签名中获取目标类 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 判断目标类是否存在引介增强,通常为false Boolean hasIntroductions = null; // 循环目标方法匹配的通知 for (Advisor advisor : advisors) { // 如果是PointcutAdvisor类型的实例 if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; // 如果提前进行过切点的匹配了或者当前的Advisor适用于目标类 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; //检测Advisor是否适用于此目标方法 if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { // 拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistry对advice织入具备很大的作用 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // 使用MethodMatchers的matches方法进行匹配判断 if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. // 动态切入点则会创建一个InterceptorAndDynamicMethodMatcher对象 // 这个对象包含MethodInterceptor和MethodMatcher的实例 for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { // 添加到列表中 interceptorList.addAll(Arrays.asList(interceptors)); } } } } // 如果是引介增强 else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { // 将Advisor转换为Interceptor Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } // 以上两种都不是 else { // 将Advisor转换为Interceptor Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
这个方法会将IOC容器中的所有的Advisor对象进行匹配,看是否符合目标对象及其方法,并筛选或封装成有实现MethodInterceptor类的对象。
registry.getInterceptors(advisor),见方法3详解
方法3:getInterceptors
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); // 从Advisor中获取 Advice Advice advice = advisor.getAdvice(); //如果有实现了MethodInterceptor接口,则添加到集合中 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { // 转换为对应的 MethodInterceptor类型 // AfterReturningAdviceInterceptor MethodBeforeAdviceInterceptor ThrowsAdviceInterceptor interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); }
这个方法判断传递进来的通知类是否有实现MethodInterceptor接口,有则直接添加到集合中。如果没有则判断是否为AfterReturningAdvice、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter的实现类,如果是的话,通过adapter.getInterceptor(advisor)方法,将advisor封装成MethodInterceptor的实现子类。
方法4:proceed
public Object proceed() throws Throwable { try { return super.proceed(); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) { throw ex; } else { throw new UndeclaredThrowableException(ex); } } }
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 从索引为-1的拦截器开始调用,并按序递增,如果拦截器链中的拦截器迭代调用完毕,开始调用被代理类的方法,这个方法是通过反射机制完成的 // 具体实现在AopUtils.invokeJoinpointUsingReflection方法中 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 获取下一个要执行的拦截器,沿着定义好的interceptorOrInterceptionAdvice链进行处理 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. // 这里对拦截器进行动态匹配的判断,这里是对pointcut触发进行匹配的地方,如果和定义的pointcut匹配,那么这个advice将会得到执行 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. // 如果不匹配,那么proceed会被递归调用,知道所有的拦截器都被运行过位置 return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // 普通拦截器,直接调用拦截器,将this作为参数传递以保证当前实例中调用链的执行 //这个方法会通过递归的方法一直调用proceed方法,直到所有的拦截器执行完毕后,执行被代理类的方法后直接返回。 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
AOP的几种增强方法
切面配置方式
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class AccountAdvice { public void before(){ System.out.println("before"); } public void after(){ System.out.println("after"); } public void around(){ System.out.println("around"); } public void afterReturn(){ System.out.println("afterReturn"); } public void afterThrow(){ System.out.println(")"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean> <bean id="myAccount" class="service.impl.MyAccount" ></bean> <aop:config > <aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/> <aop:aspect ref="accountAdvice" > <aop:after method="after" pointcut-ref="pointCut" ></aop:after> <aop:before method="before" pointcut-ref="pointCut"></aop:before> <aop:around method="around" pointcut-ref="pointCut"></aop:around> <aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning> <aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing> </aop:aspect> </aop:config> </beans>
这种配置方式,在解析过程中会将after 、before 、around 、after-returning、after-throwing 封装成Advisor对象
实现MethodInterceptor接口
从方法3中可以知道,只要实现了MethodInterceptor接口,则会被当做拦截器加入集合中,在后续的责任链调用过程中会进行调用。
public class MyAdvisor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("自定义的方法!!!1"); return invocation.proceed(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="myAccount" class="service.impl.MyAccount" ></bean> <bean id="myAdvisor" class="service.aop.MyAdvisor" ></bean> <aop:config > <aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/> <aop:advisor advice-ref="myAdvisor" pointcut-ref="pointCut"></aop:advisor> </aop:config> </beans>
实现AdvisorAdapter子接口
从方法3中我们知道,当实现了AfterReturningAdvice、MethodBeforeAdviceAdapter、ThrowsAdviceAdapter接口中任何一个接口时,只要切点符合被代理类及其方法时,会被封装成MethodInterceptor的实现子类,从而来责任链调用过程中会获取调用。
import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class MyAdvisor2 implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("自定义的afterReturning"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="myAccount" class="service.impl.MyAccount" ></bean> <bean id="myAdvisor2" class="service.aop.MyAdvisor2" ></bean> <aop:config > <aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/> <aop:advisor advice-ref="myAdvisor2" pointcut-ref="pointCut"></aop:advisor> </aop:config> </beans>
总结
AOP动态代理过程使用责任链设计模式,将符合条件的MethodInterceptor实现类进行层层调用,但是不一定MethodInterceptor集合中的所有都会被调用,如果某个MethodInterceptor执行过程中,没有调用其下层拦截器,直接返回了,则后面的拦截器不会进行调用。