《Spring技术内幕》学习笔记9——AOP通知以及编程式AOP

1.处理AOP配置的通知基本步骤:

(1).获取AOP配置的通知Advice

从上一篇博客《创建AOP代理对象并对目标对象切面拦截》对Spring中采用JDKCGLIB两种方式创建AOP动态代理的源码分析中,我们了解到,在AOP动态代理对象的回调方法中,都需要使用以下方式获取AOP配置的通知,并将获取到的通知和目标对象、代理对象等一起封装为ReflectiveMethodInvocation对象:

//获取AOP配置的通知 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); …… //根据获取的通知、目标对象等创建ReflectiveMethodInvocation //如果是CGLIB方式,则创建CglibMethodInvocation对象: //new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy); invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); //沿着获取的通知链,递归调用所有配置的AOP通知 retVal = invocation.proceed();

(2).创建ReflectiveMethodInvocation对象:

a.创建CglibMethodInvocation对象:

//CglibMethodInvocation的构造方法 public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { //调用父类ReflectiveMethodInvocation的构造方法 super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); this.methodProxy = methodProxy; this.protectedMethod = Modifier.isProtected(method.getModifiers()); }

CglibMethodInvocation继承ReflectiveMethodInvocation类,在创建时首先调用父类的初始化方法。

b.创建ReflectiveMethodInvocation对象:

//ReflectiveMethodInvocation的构造方法 protected ReflectiveMethodInvocation( Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; this.targetClass = targetClass; this.method = BridgeMethodResolver.findBridgedMethod(method); this.arguments = arguments; //将获取到的AOP通知赋值给成员变量 this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; }

(3).处理AOP配置的通知器:

Spring通过调用ReflectiveMethodInvocation类来处理AOP配置的通知,CglibMethodInvocation继承ReflectiveMethodInvocation,因此JDKCGLIB方式都是通过调用ReflectiveMethodInvocationproceed()方法来处理通知的,处理通知的源码如下:

//处理AOP配置的通知 public Object proceed() throws Throwable { //如果拦截器链中通知已经调用完毕 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { //这个方法调用AopUtils.invokeJoinpointUsingReflection方法, //通过反射机制直接调用目标对象方法 return invokeJoinpoint(); } //获取AOP配置的通知,在ReflectiveMethodInvocation初始化构方法中将获 //取到的AOP通知赋值给interceptorsAndDynamicMethodMatchers变量 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //如果获取的通知器或通知是动态匹配方法拦截器类型 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { //动态匹配方法拦截器 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { //如果匹配,调用拦截器的方法 return dm.interceptor.invoke(this); } else { //如果不匹配,递归调用proceed()方法,知道拦截器链被全部调用为止 return proceed(); } } else { //如果不是动态匹配方法拦截器,则切入点在构造对象之前进行静态匹配,调用 //拦截器的方法 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }

2.AOP代理创建辅助类AdvisedSupport获取通知:

1中我们看到,获取AOP通知的的方法如下:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

该方法会通过AOP代理创建辅助类AdvisedSupport获取AOP配置的通知,获取通知的过程如下:

(1).AdvisedSupport获取给定方法的通知:

//获取通知 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { //使用cache缓存 MethodCacheKey cacheKey = new MethodCacheKey(method); //首先从缓存中获取 List<Object> cached = this.methodCache.get(cacheKey); //如果缓存中没有,即第一次调用 if (cached == null) { //从通知器链容器中获取通知,这里使用的DefaultAdvisorChainFactory cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); //缓存获取到的通知 this.methodCache.put(cacheKey, cached); } return cached; }

通过上面的源码我们看到,AdvisedSupport第一次获取通知时,会从通知链容器DefaultAdvisorChainFactory中通过getInterceptorsAndDynamicInterceptionAdvice方法获取指定的通知。

(2).DefaultAdvisorChainFactory获取指类,指定方法的通知:

DefaultAdvisorChainFactory通过getInterceptorsAndDynamicInterceptionAdvice方法获取指定类中指定方法的通知,源码如下:

//获取通知 public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class targetClass) { //根据AOP中配置的通知器创建一个保持获取到通知的集合 List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); //判断目标类中是否引入了配置的通知 boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); //获取通知适配器注册单态模式对象 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); //遍历AOP配置的通知 for (Advisor advisor : config.getAdvisors()) { //如果通知器的类型是切入点通知器 if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; //如果AOP配置对通知已经过滤,即只包含符合条件的通知器,或者 //获取当前切入点的类过滤器匹配目标类 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { //获取通知器中的方法拦截器列表 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); //获取当前通知器切入点的方法匹配器 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //如果目标类的方法匹配切入点 if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { //如果方法匹配器是运行时动态匹配的 if (mm.isRuntime()) { //将通知器中的方法拦截器和方法匹配器封装后添加到返回的通知器集合中 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; //如果AOP通知配置是预过滤的,或者目标类符合当前通知器的类过滤器 if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { //获取通知器中所有的方法拦截器,即通知 Interceptor[] interceptors = registry.getInterceptors(advisor); //将通知添加到要返回的通知集合中 interceptorList.addAll(Arrays.asList(interceptors)); } } //如果通知类型既不是切入点通知器,又不是引入通知器 else { Interceptor[] interceptors = registry.getInterceptors(advisor); //直接将通知添加到要返回的通知集合中 interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } //检查目标类和AOP通知配置是否匹配AOP引入规则 private static boolean hasMatchingIntroductions(Advised config, Class targetClass) { //遍历所有的通知器 for (int i = 0; i < config.getAdvisors().length; i++) { Advisor advisor = config.getAdvisors()[i]; //如果通知器是引入通知器 if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; //使用当前通知器的类过滤器匹配目标类 if (ia.getClassFilter().matches(targetClass)) { return true; } } } return false; }

通过上面DefaultAdvisorChainFactory获取通知过程源码的分析,我们看到通过AdvisorAdapterRegistrygetInterceptors方法获取通知器的通知,AdvisorAdapterRegistry是一个接口,具体的实现交由其实现类DefaultAdvisorAdapterRegistry提供。

3.DefaultAdvisorAdapterRegistry获取通知器的通知:

DefaultAdvisorAdapterRegistry的源码如下:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { //持有通知适配器的集合 private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3); //构造方法,为通知适配器集合添加Spring的3种类型通知适配器 public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } //将通知封装为通知器 public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { //如果通知对象是通知器类型,则不用封装 if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; //如果通知是方法拦截器 if (advice instanceof MethodInterceptor) { //将方法拦截器类型的通知封装为默认切入点通知器 return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { //检查通知适配器是否支持给定的通知 if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } //获取通知器的通知 public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3); //通知通知器的通知 Advice advice = advisor.getAdvice(); //如果通知是方法拦截器类型,则不需要适配,直接添加到通知集合中 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } //对通知进行适配,从适配器中获取封装好AOP编制功能的拦截器 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]); } //注册通知适配器 public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); } }

从上述代码获取通知源码分析中我们看到,DefaultAdvisorAdapterRegistrygetInterceptors方法中,需要将AOP配置的通知封装为通知适配器,下面我们继续分析通知适配器的主要源码和功能。

4.通知适配器:

通知适配器AdvisorAdapter对通知进行封装,为通知提供Spring AOP的增强功能,下面我们以MethodBeforeAdviceAdapter为例,分析通知适配器的具体功能:

(1).MethodBeforeAdviceAdapter源码:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { //检查通知是否为通知适配器适配的通知类型 public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } //获取通知拦截器 public MethodInterceptor getInterceptor(Advisor advisor) { //获取通知器的通知 MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); //将通知封装为方法拦截器 return new MethodBeforeAdviceInterceptor(advice); } }

通过对MethodBeforeAdviceAdapter的源码分析,我们看到通知适配器在获取到通知器的通知后,将通知封装为方法拦截器,我们接下来分析MethodBeforeAdviceInterceptor是如何将通知封装为方法拦截器的。

(2).MethodBeforeAdviceInterceptor封装通知:

MethodBeforeAdviceInterceptor封装通知实现了Spring AOP的织入功能,其源码如下:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; //拦截器构造方法,初始化通知 public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } //拦截器的回调方法,会在代理对象的方法调用前触发回调 public Object invoke(MethodInvocation mi) throws Throwable { //在目标方法调用之前,先调用前置通知的before方法 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); //继续调用通知拦截链,调用ReflectiveMethodInvocation的proceed方法 return mi.proceed(); } }

通过对MethodBeforeAdviceInterceptor拦截器的源码分析,我们看到,SpringAOP处理的基本流程:

首先,为目标对象对象创建AOP代理对象,根据AOP配置获取通知器,通知器中持有切入点和通知。

其次,根据通知器中的切入点,获取目标类目标方法的通知,并将通知封装为拦截器,添加到代理拦截链中。

最后,调用目标对象目标方法时,调用AOP代理对象,根据通知在调用目标对象方法时触发调用通知链中通知拦截器的回调方法。

5.方法拦截器:

4中我们已经分析了MethodBeforeAdviceInterceptor源码,了解到方法拦截器主要作用是根据通知类型在调用目标方法时触发通知的回调,我们接下来分析AfterReturningAdviceInterceptorThrowsAdviceInterceptor拦截器的源码,了解对后置通知和异常通知的处理实现:

(1).AfterReturningAdviceInterceptor:

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; //后置通知拦截器构造方法,初始化通知 public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } //后置通知拦截器回调方法 public Object invoke(MethodInvocation mi) throws Throwable { //调用ReflectiveMethodInvocation的proceed方法,调用通知链 Object retVal = mi.proceed(); //通知链调用最后才调用后置通知的返回之后回调方法 this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; } }

(2).ThrowsAdviceInterceptor

异常通知拦截器ThrowsAdviceInterceptor和前置通知拦截器MethodBeforeAdviceInterceptor、后置通知拦截器AfterReturningAdviceInterceptor类似,不同之处在于需要维护异常处理器,因此更加复杂,源码如下:

public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice { private static final String AFTER_THROWING = "afterThrowing"; private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class); private final Object throwsAdvice; //key为类,value为method的异常处理map private final Map<Class, Method> exceptionHandlerMap = new HashMap<Class, Method>(); //异常通知拦截器构造方法 public ThrowsAdviceInterceptor(Object throwsAdvice) { Assert.notNull(throwsAdvice, "Advice must not be null"); //初始化异常通知 this.throwsAdvice = throwsAdvice; //获取异常通知的方法 Method[] methods = throwsAdvice.getClass().getMethods(); //遍历所有配置异常通知的方法 for (Method method : methods) { //如果方法名为"afterThrowing",且方法参数为1或4,且方法参数的父类为 //Throwable,说明异常通知中有异常处理器 if (method.getName().equals(AFTER_THROWING) && (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) && Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1]) ) { //添加异常处理器 this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method); if (logger.isDebugEnabled()) { logger.debug("Found exception handler method: " + method); } } } //没有配置异常处理器 if (this.exceptionHandlerMap.isEmpty()) { throw new IllegalArgumentException( "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]"); } } //获取异常处理器数目 public int getHandlerMethodCount() { return this.exceptionHandlerMap.size(); } //获取异常处理器 private Method getExceptionHandler(Throwable exception) { //获取给定异常类 Class exceptionClass = exception.getClass(); if (logger.isTraceEnabled()) { logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]"); } //从异常处理器map中获取给定异常类的处理器 Method handler = this.exceptionHandlerMap.get(exceptionClass); //如果异常处理器为null,且异常类不是Throwable while (handler == null && !exceptionClass.equals(Throwable.class)) { //获取异常类的基类 exceptionClass = exceptionClass.getSuperclass(); //获取基类的异常处理器 handler = this.exceptionHandlerMap.get(exceptionClass); } if (handler != null && logger.isDebugEnabled()) { logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler); } return handler; } //异常通知的回调方法 public Object invoke(MethodInvocation mi) throws Throwable { //把目标对象方法调用放入try/catch中 try { return mi.proceed(); } catch (Throwable ex) { //在catch中触发异常通知的回调 Method handlerMethod = getExceptionHandler(ex); if (handlerMethod != null) { //使用异常处理器处理异常 invokeHandlerMethod(mi, ex, handlerMethod); } //将异常向上抛出 throw ex; } } //异常处理器处理异常 private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable { Object[] handlerArgs; //如果方法只有一个参数 if (method.getParameterTypes().length == 1) { handlerArgs = new Object[] { ex }; } //获取方法的参数列表 else { handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex}; } try { //使用JDK反射机制,调用异常通知的异常处理方法 method.invoke(this.throwsAdvice, handlerArgs); } catch (InvocationTargetException targetEx) { throw targetEx.getTargetException(); } } }

6.ProxyFactory实现编程式AOP:

在上一篇博客《创建AOP代理对象并对目标对象切面拦截》中,我们以ProxyFactoryBean 为例,分析了Spring创建AOP代理对象以及对目标对象进行切面拦截的实现过程,在Spring中还有另一个创建AOP代理对象的容器——ProxyFactory,两个创建AOP代理对象容器的区别如下:

a.ProxyFactory:创建编程式的Spring AOP应用。

b.ProxyFactoryBean:创建声明式的Spring AOP应用。

我们现在通过分析ProxyFactory源码,了解Spring编程式AOP应用的具体实现:

(1).使用ProxyFactory编程式AOP应用的简单例子:

//获取目标对象 TargetImpl target = new TargetImpl(); //创建目标对象的代理工厂 ProxyFactory aopFactory = new ProxyFactory(target); //为目标对象代理工厂添加通知器 aopFactory.addAdvisor(要添加的Advisor); //为目标对象代理工厂添加通知 aopFactory.addAdvice(要添加的Advice); //获取目标对象的代理 TargetImpl targetProxy = (TargetImpl)aopFactory.getProxy();

(2).ProxyFactory源码:

public class ProxyFactory extends ProxyCreatorSupport { //创建一个空的AOP代理容器 public ProxyFactory() { } //为目标对象创建AOP代理容器 public ProxyFactory(Object target) { Assert.notNull(target, "Target object must not be null"); setInterfaces(ClassUtils.getAllInterfaces(target)); setTarget(target); } //根据代理接口创建AOP代理容器 public ProxyFactory(Class[] proxyInterfaces) { setInterfaces(proxyInterfaces); } //为指定代理接口和拦截器创建AOP代理容器 public ProxyFactory(Class proxyInterface, Interceptor interceptor) { //为代理对象添加代理接口 addInterface(proxyInterface); //为代理对象添加拦截器 addAdvice(interceptor); } //根据指定目标源和代理接口创建代理容器 public ProxyFactory(Class proxyInterface, TargetSource targetSource) { addInterface(proxyInterface); //为通知设置目标源 setTargetSource(targetSource); } //获取AOP代理 public Object getProxy() { return createAopProxy().getProxy(); } //使用指定类加载器创建AOP代理 public Object getProxy(ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); } //获取指定代理接口和拦截器的AOP代理 public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) { return (T) new ProxyFactory(proxyInterface, interceptor).getProxy(); } //获取指定代理接口和目标源的AOP代理 public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) { return (T) new ProxyFactory(proxyInterface, targetSource).getProxy(); } //为指定目标源创建AOP代理 public static Object getProxy(TargetSource targetSource) { if (targetSource.getTargetClass() == null) { throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class"); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTargetSource(targetSource); proxyFactory.setProxyTargetClass(true); return proxyFactory.getProxy(); } }

通过上述对ProxyFactory源码的分析可以看出,获取代理对象的getProxy()方法中,调用ProxyCreatorSupportcreateAopProxy()方法获得DefaultAopProxyFactory对象,通过调用DefaultAopProxyFactory类的createAopProxy方法来调用JDK或者CGLIB创建AOP代理对象,与ProxyFactoryBean实现原理相同,通知的配置以及方法的通知链拦截调用等都与ProxyFactoryBean完全相同,这里不再赘述,请实现参考上一篇博客对ProxyFactoryBean的分析。

你可能感兴趣的:(spring,AOP,编程,ClassLoader,object,Interceptor)