RedCloud Help

SpringAOP

代码地址

Spring AOP的应用场景

AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP设置模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。我们现在做的一些非业务,如:日志、事物、安全等都会写在业务代码中(也即是说,这些非业务类横切与业务类),但这些代码往往是重复,复制,粘帖式的代码会给程序的维护带来不便,AOP就实现了吧这些业务需求与系统需求分开来做。这种解决的方式也称代理机制。

AOP中必须明白的几个概念

1、切面(Aspect)

官方的抽象定义为:一个关注点的模块化,这个关注点可能会横切多个对象。切面在applicationContext中aop:aspect来配置。

连接点(Joinpoint):程序执行过程中的某一行为,例如,MemberService.get的调用或者MemberService.delete抛出异常等行为。

2、通知(Advice)

切面对于某个连接点所产生的动作。其中,一个切面包含多个advice。

3、切入点(Pointcut)

匹配连接点的断言,在AOP中通知和一个切入点表达式关联。切面中的所有通知所关注的连接点,都由切入点表达式来决定。

4、目标对象(Target Object)

被一个或者多个切面所通知的对象。例如,AServiceImpl和BServiceImpl,当然在实际运行时,SpringAOP采用代理实现,实际AOP操作的是TargetObject的代理对象。

5、AOP代理(AOP Proxy)

在Spring AOP中有两种代理方式,JDK动态代理和CGLib代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,例如AserviceImpl;反之,采用CGLib代理,例如,BServiceImpl。强制使用CGLib代理需要将aop:config的proxy-target-class属性设为true。 通知Advice类型

6、前置通知(Before Advice)

在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在aop:aspect里面使用aop:before元素进行声明。例如,TestAspect中的doBefore方法。

7、后置通知(After Advice)

当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在aop:aspect里面使用aop:after元素进行生命。

8、返回后通知(After Return Advice)

在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在aop:aspect里面使用 元素进行声明。

9、环绕通知(Around Advice)

包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在aop:aspect里面使用aop:around元素进行声明。

10、异常通知(After Throwing Advice)

在方法抛出异常退出时执行的通知。ApplicationContext中在aop:aspect里面使用aop:after-throwing元素进行声明。

注:可以将多个通知应用到一个目标对象上,即可以将多个切面治入到同一个目标对象。

使用Spring Aop可以基于两种方式,一种是比较方便和强大的注解方式,另外一种是中规中矩的xml配置方式。

Xml 配置方式

application-context.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 注解驱动加上这句话 --> <!--<aop:aspectj-autoproxy proxy-target-class="true"/>--> <bean id="xmlAspect" class="cn.jihongyun.aop.aspect.XmlAspect"></bean> <bean id="xmlCutPointService" class="cn.jihongyun.aop.service.XmlCutPointService"></bean> <!--AOP配置 --> <aop:config> <!--声明一个切面,并注入切面Bean,相当于@Aspect --> <aop:aspect ref="xmlAspect" > <!--配置一个切入点,相当于@Pointcut --> <aop:pointcut expression="execution(* cn.jihongyun.aop.service..*(..))" id="simplePointcut"/> <!--配置通知,相当于@Before、@After、@AfterReturn、@Around、@AfterThrowing --> <aop:before pointcut-ref="simplePointcut" method="before"/> <aop:after pointcut-ref="simplePointcut" method="after"/> <aop:after-returning pointcut-ref="simplePointcut" method="afterReturn"/> <aop:after-throwing pointcut-ref="simplePointcut" method="afterThrow" throwing="ex"/> <aop:around pointcut-ref="simplePointcut" method="around"/> </aop:aspect> </aop:config> </beans>

切面类

package cn.jihongyun.aop.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import java.util.logging.Logger; /** * XML版本Aspect切面 */ public class XmlAspect { private final static Logger logger = Logger.getLogger("XmlAspect"); /** * 配置前置通知,使用方法aspect()上注册的切入点 * 同时接受Joinpoint切入点对象,可以没有参数 * @param joinpoint */ public void before(JoinPoint joinpoint) { logger.info("before" + joinpoint); } // 配置后置通知,使用在方法 public void after(JoinPoint joinpoint) { logger.info("after" + joinpoint); } // 配置环绕通知,使用方法aspect() 上注册的切入点 public void around(JoinPoint joinpoint) { long start = System.currentTimeMillis(); try { ((ProceedingJoinPoint) joinpoint).proceed(); long end = System.currentTimeMillis(); logger.info("around"+joinpoint+"\tUse time : "+(end - start )+"ms!"); } catch (Throwable e) { long end = System.currentTimeMillis(); logger.info("around"+joinpoint+"\tUse time : "+(end - start )+"ms with Exception : "+e.getMessage()); } } // 配置后置返回通知,使用在方法aspect()上注册的切入点 public void afterReturn(JoinPoint joinpoint) { logger.info("afterReturn " + joinpoint); } // 配置抛出异常后通知,使用在方法aspect()上注册的切入点 public void afterThrow(JoinPoint joinpoint, Exception ex) { logger.info("afterThrow " + joinpoint + "\t" + ex.getMessage()); } }

切入点

package cn.jihongyun.aop.service; import java.util.logging.Logger; public class XmlCutPointService { private final static Logger log = Logger.getLogger("XmlCutPointService"); public Boolean normal(Long normal) { log.info("normal() execute!"); return Boolean.TRUE; } public Boolean exception(Long exception) { log.info("exception() execute!"); throw new RuntimeException("unknown"); } }

测试类

package cn.jihongyun.aop.test; import cn.jihongyun.aop.service.XmlCutPointService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class XmlTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); XmlCutPointService xm = (XmlCutPointService) context.getBean("xmlCutPointService"); xm.normal(1L); System.out.println("=================================="); xm.exception(11L); } }

测试日志

十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect before 信息: beforeexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.normal(Long)) 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.service.XmlCutPointService normal 信息: normal() execute! 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect around 信息: aroundexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.normal(Long)) Use time : 14ms! 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect afterReturn 信息: afterReturn execution(Boolean cn.jihongyun.aop.service.XmlCutPointService.normal(Long)) 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect after 信息: afterexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.normal(Long)) 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect before 信息: beforeexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.exception(Long)) 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.service.XmlCutPointService exception 信息: exception() execute! 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect around 信息: aroundexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.exception(Long)) Use time : 0ms with Exception : unknown 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect afterReturn 信息: afterReturn execution(Boolean cn.jihongyun.aop.service.XmlCutPointService.exception(Long)) 十月 26, 2021 1:45:42 下午 cn.jihongyun.aop.aspect.XmlAspect after 信息: afterexecution(Boolean cn.jihongyun.aop.service.XmlCutPointService.exception(Long)) ================================== Process finished with exit code 0

注解驱动方式

使用注解配置Spring AOP总体分为两步,第一步是在xml文件中生命激活自动扫描组件功能,同时激活自动代理功能(来测试AOP的注解功能):

xml配置

<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="cn.jihongyun"/> <!--注解驱动需要加上这个配置--> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- <import resource="application-aop.xml"/>--> </beans>

切面

package cn.jihongyun.aop.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.logging.Logger; @Component @Aspect public class AnnotationAspect { private final static Logger logger = Logger.getLogger("AnnotationAspect"); @Pointcut("execution(* cn.jihongyun.aop.service..*(..))") public void aspect() { } @Before("aspect()") public void before(JoinPoint joinpoint) { logger.info("before" + joinpoint); } // 配置后置通知,使用在方法 @After("aspect()") public void after(JoinPoint joinpoint) { logger.info("after" + joinpoint); } // 配置环绕通知,使用方法aspect() 上注册的切入点 @Around("aspect()") public void around(JoinPoint joinpoint) { long start = System.currentTimeMillis(); try { ((ProceedingJoinPoint) joinpoint).proceed(); long end = System.currentTimeMillis(); logger.info("around"+joinpoint+"\tUse time : "+(end - start )+"ms!"); } catch (Throwable e) { long end = System.currentTimeMillis(); logger.info("around"+joinpoint+"\tUse time : "+(end - start )+"ms with Exception : "+e.getMessage()); } } // 配置后置返回通知,使用在方法aspect()上注册的切入点 @AfterReturning("aspect()") public void afterReturn(JoinPoint joinpoint) { logger.info("afterReturn " + joinpoint); } // 配置抛出异常后通知,使用在方法aspect()上注册的切入点 @AfterThrowing(pointcut = "aspect()",throwing = "ex") public void afterThrow(JoinPoint joinpoint, Exception ex) { logger.info("afterThrow " + joinpoint + "\t" + ex.getMessage()); } }

切入点

package cn.jihongyun.aop.service; import org.springframework.stereotype.Service; import java.util.logging.Logger; @Service public class AnnotationCutPointService { private final static Logger log = Logger.getLogger("AnnotationCutPointService"); public Boolean normal(Long normal) { log.info("normal() execute!"); return Boolean.TRUE; } public Boolean exception(Long exception) { log.info("exception() execute!"); throw new RuntimeException("unknown"); } }

测试类

package cn.jihongyun.aop.test; import cn.jihongyun.aop.service.AnnotationCutPointService; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnotationAspectTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml"); AnnotationCutPointService xm = context.getBean(AnnotationCutPointService.class); xm.normal(1L); xm.exception(11L); } }

测试日志

十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect before 信息: beforeexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.normal(Long)) 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.service.AnnotationCutPointService normal 信息: normal() execute! 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect around 信息: aroundexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.normal(Long)) Use time : 15ms! 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect after 信息: afterexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.normal(Long)) 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect afterReturn 信息: afterReturn execution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.normal(Long)) 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect before 信息: beforeexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.exception(Long)) 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.service.AnnotationCutPointService exception 信息: exception() execute! 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect around 信息: aroundexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.exception(Long)) Use time : 1ms with Exception : unknown 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect after 信息: afterexecution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.exception(Long)) 十月 26, 2021 2:27:58 下午 cn.jihongyun.aop.aspect.AnnotationAspect afterReturn 信息: afterReturn execution(Boolean cn.jihongyun.aop.service.AnnotationCutPointService.exception(Long))

Spring AOP源码分析

时序图

创建代理对象

ProxyCreatorSupportProxyFactoryAbstractAutoProxyCreatorAbstractAutowireCapableBeanFactoryProxyCreatorSupportProxyFactoryAbstractAutoProxyCreatorAbstractAutowireCapableBeanFactoryinitializeBean1applyBeanPostProcessorsBeforeInitialization2posProcessAfterInitialization3wrapIfNecessary4createProxy5getProxy6createAopProxy7返回具体的ProxyFactory8

调用

AbstractAutoProxyCreatorReflectiveMethodInvocationAdvisedSupportJdkDynamicAopProxyAbstractAutoProxyCreatorReflectiveMethodInvocationAdvisedSupportJdkDynamicAopProxygetInterceptorsAndDynamicInterceptorsAdvice1proceed2invokeJoinpointUsingReflection3

寻找入口

Spring的Aop是通过接入BeanPostProcessor后置处理器开始的,它是Spring IOC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器出发的Bean生命周期事件。后置处理器向容器注册以后,容器中管理的Bean就具备了接受IOC容器时间回调的能力。

BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件设置即可。

BeanPostProcessor源码

public interface BeanPostProcessor { /** * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * <p>The default implementation returns the given {@code bean} as-is. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; * if {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet */ // 为在bean的初始化前提供回调入口 @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean * instance and the objects created by the FactoryBean (as of Spring 2.0). The * post-processor can decide whether to apply to either the FactoryBean or created * objects or both through corresponding {@code bean instanceof FactoryBean} checks. * <p>This callback will also be invoked after a short-circuiting triggered by a * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method, * in contrast to all other BeanPostProcessor callbacks. * <p>The default implementation returns the given {@code bean} as-is. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; * if {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet * @see org.springframework.beans.factory.FactoryBean */ // 为在bean的初始化之后提供回调入口 @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }

这两个回调的入口都是和容器管理的bean生命周期事件紧密相关,可以为用户提供在Spring IOC容器初始化bean过程中自定义处理的操作。

2、AbstractAutowireCapableBeanFactory类对容器生成的bean添加后置处理器

BeanPostProcessor后置处理器的调用发生在Spring IOC容器完成对Bean实例对象的创建和属性的依赖注入完成之后,在对Spring依赖注入的源码分析过程中我们知道,当应用程序第一次调用getBean()方法(lazy-init预实例化除外)向Spring IOC容器索取指定Bean时触发Spring IOC容器创建Bean实例对象并进行依赖注入的过程,其实真正实现创建Bean对象并进行依赖注入的方法是AbstractAutowireCapbleBeanFactory类的doCreateBean()方法,主要源码如下:

// 真正创建Bean的方法 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { ... // Initialize the bean instance. // Bean对象的初始化,依赖注入在此出发 // 这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean Object exposedObject = bean; try { // 将Bean实例对象封装,并且Bean定义中配置的属性值赋值 populateBean(beanName, mbd, instanceWrapper); // 在对bean实例对象生成和依赖注入完成以后,开始对bean实例对象 // 进行初始化,为bean实例对象应用beanPostProcessor后置处理器 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } ... // Register bean as disposable. // 注册完成以来注入的bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }

从上面的代码中我们知道,为Bean实例对象添加BeanPostProcessor后置处理器的入口是initializeBean()方法。

3、iniitializeBean()方法为容器产生bean实例对象添加BeanPostProcessor后置处理器

同样在AbstractAutowireCapableBeanFactory类中,initializeBean()方法实现为容器创建的Bean实例对象添加BeanPostProceessor后置处理器,源码如下:

// 初始化容器创建的bean实例对象,为其添加BeanPostProcessor后置处理器 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { // JDK的安全机制验证权限 if (System.getSecurityManager() != null) { // 实现PrivilegedAction接口的匿名内部类 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // 为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; // 对BeanPostProcessor后置处理器的postProcessBeforeInitialization // 回调方法的调用,为Bean实例初始化前做一些处理 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } // 调用bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置 // 文件中通过init-Method属性指定的 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } // 对BeanPostProcessor后置处理器的postProcessAfterInitialization // 回调方法的调用,为Bean实例初始化之后做一些处理 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } // 调用BeanPostProcessor后置处理器实例对象初始化之前的处理方法 @Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历容器为所创建的bean添加的所有BeanPostProcessor后置处理器 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { // 调用bean实例所有的后置处理中的初始化前处理方法,为Bean实例对象在 // 初始化之前做一些自定义的处理操作 Object current = beanProcessor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; } @Override // 调用BeanPostProcessor后置处理器实例对象初始化之后的处理方法 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历容器为所创建的bean添加的所有BeanPostProcessor后置处理器 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { // 调用bean实例所有的后置处理中的初始化后处理方法,为bean实例对象在 // 初始化之后做一些自定义的处理操作 Object current = beanProcessor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }

BeanPostProcessor是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring中,BeanPostProcessor的实现子类非常的多,分别完成不同的操作,如:AOP面向切面编程的注册通知适配器、bean对象的数据验证、bean继承属性、方法的合并等等,我们以简单的AOP切面织入来简单了解其主要功能。下面我们来分析其中一个创建AOP代理对象的子类AbstractAutoProxyCreator类。该类重写了postProcessAfterInitialization()方法。

选择代理策略

进入postProcessAfterInitialization()方法,我们发现调用一个非常核心的方法wrapIfNecessary(),其源码如下:

@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 判断是否需要代理这个bean if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 判断是否是一些infrastructureClass或者是否应该跳过这个bean // 所谓infrastructureClass就是指Advice/PointCut/Advisor等接口的实现类 // shouldSkip默认实现为返回false,由于是protected方法,子类可以覆盖 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 获取这个bean的advice Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(getProxyClassLoader()); }

整个过程跟下来,我们发现最终调用的是proxyFactory.getProxy()方法。到这里我们大概能够猜到proxyFactory有JDK和CGLib的,哪么我们该如何选择呢?最终调用的是DefaultAopProxyFactory的createAopProxy()方法:

@SuppressWarnings("serial") public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } /** * Determine whether the supplied {@link AdvisedSupport} has only the * {@link org.springframework.aop.SpringProxy} interface specified * (or no proxy interfaces specified at all). */ private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }

调用代理方法

分析一下Spring 中主要的AOP组件:

«interface»
TargetClassAware
«interface»
Advised
«interface»
AopProxy
«interface»
Advice
«interface»
Interceptor
«interface»
MethodInterceptor
«interface»
Advisor
«interface»
PointcutAdvisor
«interface»
AopProxyFactory
AdvisedSupport
ProxyConfig
AbstractAutoProxyCreator
ProxyCreatorSupport
ProxyFactory
ProxyFactoryBean
CglibAopProxy
JdkDynamicAopProxy
DefaultAopProxyFactory

上面我们已经了解到了Spring提供了两种方式来生成代理方式有JDKProxy和CGLib。下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中,直接上相关代码:

/** * 获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy,Advised(opaque=false) * 检查上面所得到的接口中有没有定义equals或者hashcode的接口 * 调用Proxy.newProxyInstance创建代理对象 * @param classLoader the class loader to create the proxy with * (or {@code null} for the low-level proxy facility's default) * @return */ @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

通过注释我们已经看到非常明白代理对象的生成郭广昌,此处不再赘述。下面的问题是,代理对象生成了,哪切面是如何织入的?

我们知道InvocationHandler是JDK动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。而从JdkDynamicAopProxy的源码我们可以看到这个类其实也实现了InvocationHandler,下面我们分析Spring AOP是如何织入切面的,直接上源码看invoke()方法:

@Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { // equals()方法,具目标对象未实现此方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } // hashCode()方法,具目标对象未实现此方法 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { // There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } // Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; 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); // Get the interception chain for this method. // 获取可以应用到此方法上的Interceptor类 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. // 如果没有可以应用到此方法的通知(interceptor),此直接反射调用Method.invoke(target,args) if (chain.isEmpty()) { // 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... // 创建MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }

主要实现思路可以简述为:首先获取应用到方法上的通知链(Interceptor Chain)。如果有通知,则应用通知,并执行JoinPoint;如果没有通知,则直接反射执行JoinPoint。而这里的关键是通知链是如何获取的以及它是如何执行的呢?现在逐一分析。首先,从上面的代码可以看出,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看这个方法的实现逻辑:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }

通过上面的源码我们可以看出,实际获取通知的实现逻辑其实是由AdvisorChainFactory的getInterceptorsAndDynamicInterceptionAdvice()方法来实现的,且获取到的结果会被缓存。下面来分析getInterceptorsAndDynamicInterceptionAdvice()方法的实现.

@Override 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. List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 查看是否包含IntroductionAdvisor boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); // 这里实际注册一系列AdvisorAdapter,用于将Advisor转换为MethodInterceptor AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 这个地方这两个方法的位置可以互换下 // 将Advisor转换为Interceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // 检查当前advisor的pointcut是否可以匹配当前方法 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. 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)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }

这个方法执行完成后,Advised中配置能够应用到连接点(JoinPoint)或者目标类(Target Object)的Advisor全部转化成了MethodInterceptor,接下来我们再看下得到的拦截器链是怎么起作用的。

// 如果没有可以应用到此方法的通知(interceptor),此直接反射调用Method.invoke(target,args) if (chain.isEmpty()) { // 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // We need to create a method invocation... // 创建MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); }

从这段代码可以看出,如果得到的拦截器为空,则直接反射调用目标方法,否则创建MetthoInvocation,调用proceed()方法,出发拦截器链的执行,来看下具体代码:

@Override @Nullable public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 如果Interceptor执行完成,则执行JoinPoint if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } 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. // 如果要动态匹配joinPoint InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; // 动态匹配:运行时参数是否满足匹配条件 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. // 动态匹配失败时,略过当前interceptor,调用下一个Intercepter return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // 执行当前Interceptor return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }

至此,通知链就完美地形成了。我们再往下看invokeJoinpointUsingReflection()方法,其实就是反射调用:

@Nullable public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable { // Use reflection to invoke the method. try { ReflectionUtils.makeAccessible(method); return method.invoke(target, args); } catch (InvocationTargetException ex) { // Invoked method threw a checked exception. // We must rethrow it. The client won't see the interceptor. throw ex.getTargetException(); } catch (IllegalArgumentException ex) { throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex); } catch (IllegalAccessException ex) { throw new AopInvocationException("Could not access method [" + method + "]", ex); } }

触发通知

在为AopProxy代理对象配置拦截器的实现中,有一个取得拦截器的配置过程,这个过程是由DefaultAdvisorChainFactory实现的,这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一个适配器和注册过程,通过Spring预先设计好的拦截器,Spring加入了它对AOP实现的处理。

/** * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor。如果是introductionAdvisor * 则判断此Advisor能否应用到目标类targetClass上。如果是PointcutAdvisor,则判断此Advisor能否应用到目标方法 * method上,将满足条件的Advisor通过AdvisorAdaptor转换为Interceptor列表返回 * @param config the AOP configuration in the form of an Advised object * @param method the proxied method * @param targetClass the target class (may be {@code null} to indicate a proxy without * target object, in which case the method's declaring class is the next best option) * @return */ @Override 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. List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 查看是否包含IntroductionAdvisor boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); // 这里实际注册一系列AdvisorAdapter,用于将Advisor转换为MethodInterceptor AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 这个地方这两个方法的位置可以互换下 // 将Advisor转换为Interceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); // 检查当前advisor的pointcut是否可以匹配当前方法 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. 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)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }

GlobalAdvisorAdapterRegistry负责拦截器的适配和注册过程。

public abstract class GlobalAdvisorAdapterRegistry { /** * Keep track of a single instance so we can return it to classes that request it. */ private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry(); /** * Return the singleton {@link DefaultAdvisorAdapterRegistry} instance. */ public static AdvisorAdapterRegistry getInstance() { return instance; } /** * Reset the singleton {@link DefaultAdvisorAdapterRegistry}, removing any * {@link AdvisorAdapterRegistry#registerAdvisorAdapter(AdvisorAdapter) registered} * adapters. */ static void reset() { instance = new DefaultAdvisorAdapterRegistry(); } }

而GlobalAdvisorAdapterRegistry起到了适配器和单例模式的作用,提供了一个DefaultAdvisorAdapterRegistry,它用来完成各种通知的适配和注册过程。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); /** * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override 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) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } 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()]); } @Override public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); } }

DefaultAdvisorAdapterRegistry设置了一系列的配置,正是这些适配器的实现,为Spring Aop提供了编织能力。下面MethodBeforeAdviceAdapter为例,看具体的实现:

@SuppressWarnings("serial") class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { @Override public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } @Override public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); } }

Spring AOp为了实现advice的织入,设计了特定的拦截器对这些功能进行封装。我们接着看MethodBeforeAdviceInterceptor如何完成封装的?

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */ public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); } }

可以看出,invoke方法中,首先出发了advice的before回调,然后才是proceed.AfterReturningAdviceInterceptor的源码:

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; /** * Create a new AfterReturningAdviceInterceptor for the given advice. * @param advice the AfterReturningAdvice to wrap */ public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; } }

ThrowsAdviceInterceptor的源码:

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; /** Methods on throws advice, keyed by exception class */ private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<>(); /** * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice. * @param throwsAdvice the advice object that defines the exception * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice} * implementation) */ public ThrowsAdviceInterceptor(Object throwsAdvice) { Assert.notNull(throwsAdvice, "Advice must not be null"); this.throwsAdvice = throwsAdvice; Method[] methods = throwsAdvice.getClass().getMethods(); for (Method method : methods) { if (method.getName().equals(AFTER_THROWING) && (method.getParameterCount() == 1 || method.getParameterCount() == 4) && Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterCount() - 1]) ) { // Have an exception handler this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterCount() - 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(); } /** * Determine the exception handle method. Can return null if not found. * @param exception the exception thrown * @return a handler for the given exception type */ @Nullable private Method getExceptionHandler(Throwable exception) { Class<?> exceptionClass = exception.getClass(); if (logger.isTraceEnabled()) { logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]"); } Method handler = this.exceptionHandlerMap.get(exceptionClass); while (handler == null && exceptionClass != 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; } @Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { 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.getParameterCount() == 1) { handlerArgs = new Object[] { ex }; } else { handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex}; } try { method.invoke(this.throwsAdvice, handlerArgs); } catch (InvocationTargetException targetEx) { throw targetEx.getTargetException(); } } }

至此,我们知道了目标对象的增强是通过拦截器实现的。

03 May 2025