Spring AOP 源码走读
Spring版本
Version 5.0.8.RELEASE
官方文档
用法
添加依赖
引入AOP依赖
<!-- spring-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
启用自动代理
-
如果为web应用
基本都是spring-boot应用了吧,引入了spring-boot-starter-web依赖,这时候不需要任何配置,自动代理会默认启用。
实际上这是web依赖中包含了自动装配依赖(spring-boot-autoconfigure
),自动装配项目中包含了自动代理配置,并默认自动装配(spring.factories)。
自动装配依赖
自动装配指定配置类
自动装配项目依赖中的自动代理配置
-
如果非web项目
实际上就是没有引入自动装配依赖spring-boot-autoconfigure
,这时候在配置类(@Configurable修饰)上添加注解@EnableAspectJAutoProxy即可。@Configuration @EnableSpringConfigured public class AppConfig {}
启用了自动代理后,spring刷新期间,会自动注册AnnotationAwareAspectJAutoProxyCreator,处理@Aspect注解修饰的bean,生成动态代理。
自定义切面增强bean
方式一:使用注解
@Aspect// 指定该bean为自动代理切面增强
@Component// 指定该类为bean
public class DemoAspect {
@Pointcut("execution(* xxx.xxx..*.*(..))")// the pointcut expression 切入点表达式
private void pointcut() {}// the pointcut signature
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("aspect before");
}
}
方式二:自定义Advisor
自定义通知方法
public class XxxThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(IllegalStateException ex) {
System.out.println("XxxThrowsAdvice done");
}
}
自定义Advisor,并注册到上下文中
// 注册到上下文
@Component
public class DemoThrowsAdvisor implements PointcutAdvisor {
// 切入点定义
@Override
public Pointcut getPointcut() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* xxx.xxx..*.*(..))");
return pointcut;
}
// 返回自定义通知增强对象
@Override
public Advice getAdvice() {
return new DemoThrowsAdvice();
}
@Override
public boolean isPerInstance() {
return false;
}
}
以上为spring aop的简单用法,更多详细的用法强烈建议参考官网文档。
原理
很多人都知道Spring AOP底层是通过jdk动态代理和Cglib实现的,这里就通过一个jdk动态代理的简单demo(参照了spring aop实现)说明AOP原理,demo只实现后置增强。
需求
提供一个抽象类AfterAdvice,可通过继承该类自定义后置增强切面(开放闭合);
当存在多个切面增强时,链式执行;
通过jdk生成动态代理时,可灵活设置切面增强;
demo
目标接口 Animal 和目标类 Dog
public interface Animal {
void sound();
}
public class Dog implements Animal{
@Override
public void sound() {
System.out.println("汪汪~");
}
}
连接点接口 JoinPoint
连接点(JoinPoint)可以理解为被拦截的真正代码,如实现方法拦截,连接点指的就是被拦截的实际执行的方法,如上面的Animal#sound()。Spring中连接点目前指的是方法。
public interface JoinPoint {
Object proceed() throws Throwable;
}
通知(增强)接口 Advice
通知(Advice),也叫增强,可以理解为拦截到指定连接点前后时,需要执行的切面方法。
public interface Advice {
Object invoke(JoinPoint invocation) throws Throwable;
}
实现Advice接口,提供后置增强规范类 AfterAdvice,用户通过继承该规范类自定义后置增强方法。
public abstract class AfterAdvice implements Advice{
@Override
public Object invoke(JoinPoint invocation) throws Throwable {
try {
return invocation.proceed();
}
finally {
afterAdviceMethod();
}
}
protected abstract void afterAdviceMethod();
}
通过继承自定义后置增强切面
public class CustomAfterAdvice extends AfterAdvice{
@Override
protected void afterAdviceMethod() {
System.out.println("执行后置增强");
}
}
存在多个切面增强时,通过组合Advice和JoinPoint ,设计为一个切面增强链,如下:
public class ReflectiveMethodInvocation implements JoinPoint {
protected final Object target;// 目标对象
protected final Method method;// 拦截的方法
protected Object[] arguments;// 方法入参
protected final List<Advice> interceptors;// 切面增强数组
private int currentInterceptorIndex = -1;// 切面增强链执行到的下标
// 构造方法
protected ReflectiveMethodInvocation(Object target, Method method, Object[] arguments,
List<Advice> interceptors) {
this.target = target;
this.method = method;// 如果是桥接方法,则转换为原始方法
this.arguments = arguments;
this.interceptors = interceptors;
}
// 通过currentInterceptorIndex字段,一个节点一个节点执行切面
public Object proceed() throws Throwable {
// 已经执行完切面增强链,直接反射调用实际方法
if (this.currentInterceptorIndex == this.interceptors.size() - 1) {
return method.invoke(target, arguments);
}
// 执行下一个切面
return this.interceptors.get(++this.currentInterceptorIndex).invoke(this);
}
}
继承Jdk动态代理的InvocationHandler,实现切面增强的注入 JdkInvocationHandler
public class JdkInvocationHandler implements InvocationHandler {
private final Object target; // 目标对象
private final List<Advice> advices;// 切面增强集合
public JdkInvocationHandler(Object target) {
this.target = target;
this.advices = Arrays.asList(advices);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
// 增强为空,直接执行
if (advices.isEmpty()) {
result = method.invoke(target, args);
}
// 构造切面增强链,执行
else {
ReflectiveMethodInvocation chains = new ReflectiveMethodInvocation(target, method, args, advices);
result = chains.proceed();
}
return result;
}
}
测试
public class Test {
public static void main(String[] args) {
// 被代理的目标对象
Dog target = new Dog();
// 被代理的目标类
Class clazz = Dog.class;
// 自定义后置增强
Advice advice = new CustomAfterAdvice();
// 生成InvocationHandler
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(target, advice);
// 生成jdk动态代理
Animal proxy = (Animal) Proxy.newProxyInstance(clazz.getClassLoader(),
clazz.getInterfaces(), jdkInvocationHandler);
// 执行代理
proxy.sound();
}
}
执行输出
汪汪~
执行后置增强
Process finished with exit code 0
以上就是spring aop的jdk动态代理最最最简陋的demo实现(请务必当做伪代码看待),很多细节(桥接方法处理,判空,参数校验等)和内容(注解解析,拦截匹配等)都没在demo内体现。
源码
容器启动刷新,自动注册BeanFactoryPostProcessor,其中bean工厂后置处理器ConfigurationClassPostProcessor会解析配置类 @Configuration,注册@Import指定全限定名类bd等等流程,在这里不细说,请参考另外一篇文章 【AnnotationConfigApplicationContext启动源码解读】。
@EnableAspectJAutoProxy配置,引入AspectJAutoProxyRegistrar.class
AspectJAutoProxyRegistrar
是一个ImportBeanDefinitionRegistrar
实现类,会向容器中注册bean后置处理器AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition。
bean后置处理器AnnotationAwareAspectJAutoProxyCreator
便是自动代理的具体实现。
AnnotationAwareAspectJAutoProxyCreator 类结构图
这里主要关注几个核心类:
(命名的重要性,其实看类名,大致都可以推断每个类的功能,加上继承是为了实现扩展,就很好理解了)
类名 | 说明 |
---|---|
AbstractAutoProxyCreator | 实现BeanPostProcessor,为符合条件的bean创建代理对象 |
AbstractAdvisorAutoProxyCreator | 通用自动代理创建器,基于检测到的advisor,为特定bean构建AOP代理。 (扩展advisor的检测,通过指定beanClass为Advisor.class查找) BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class, true, false); |
AspectJAwareAdvisorAutoProxyCreator | 公开AspectJ的上下文调用,并在多个Advice来自同一Aspect时处理Advice的优先级规则。 (扩展advisor的优先级规则) |
AnnotationAwareAspectJAutoProxyCreator | 处理当前应用程序上下文中的所有AspectJ相关注解,以及Spring Advisors。 (扩展advisor的获取,不指定beanClass,符合条件(AspectJ)就封装为advisor) BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class, true, false); |
接下来从 AbstractAutoProxyCreator
开始走读源码,分析每个类具体功能的实现。
AbstractAutoProxyCreator
实现的相关BeanPostProcessor接口有
其中有效的方法实现为:
SmartInstantiationAwareBeanPostProcessor#predictBeanType
SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
BeanPostProcessor#postProcessAfterInitialization
方法 | 调用时机 |
---|---|
predictBeanType | 需要预测指定bean的最终类型时 |
postProcessBeforeInstantiation | 实例化前 AbstractAutowireCapableBeanFactory#createBean 484 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 1033 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation |
getEarlyBeanReference | 允许循环引用时 AbstractAutowireCapableBeanFactory#createBean 495 AbstractAutowireCapableBeanFactory#doCreateBean 566 DefaultSingletonBeanRegistry#addSingletonFactory(函数接口) 其他bean初始化调用DefaultSingletonBeanRegistry#getSingleton(String)时, 会真正调用该方法 |
postProcessAfterInitialization | 初始化后 AbstractAutowireCapableBeanFactory#createBean 495 AbstractAutowireCapableBeanFactory#doCreateBean 573 AbstractAutowireCapableBeanFactory#initializeBean 1703 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization |
根据方法名,可以很清楚方法执行顺序。
predictBeanType
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
@Nullable
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
// 如果代理缓存为空,则返回null
if (this.proxyTypes.isEmpty()) {
return null;
}
// 获取缓存key
// beanName不为空,如果beanClass为FactoryBean,则返回 '&'+beanName,否则返回beanName
// beanName为空,返回beanClass
Object cacheKey = getCacheKey(beanClass, beanName);
return this.proxyTypes.get(cacheKey);
}
}
创建代理时,会进行将类型存储到proxyTypes
缓存中。
postProcessBeforeInstantiation
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 获取缓存key
Object cacheKey = getCacheKey(beanClass, beanName);
// beanName为空 或 目标源bean缓存不包含beanName
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 如果advisedBeans包含,则返回空
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// beanClass为基础类(Advice/Pointcut/Advisor/AopInfrastructureBean)
// 或 shouldSkip(beanClass, beanName) true
// 此时不对该bean进行自动代理操作,添加advisedBeans缓存,返回null
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
// 如果我们有一个自定义的TargetSource,在这里创建代理。
// 抑制目标bean不必要的默认实例化:TargetSource将以自定义方式处理目标实例。
// 使用TargetSourceCreator为bean实例创建目标源TargetSource
// TargetSource是目标bean的一个各种基础属性集合的封装类
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
// 添加缓存targetSourcedBeans
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 获取bean相关的切面通知
// getAdvicesAndAdvisorsForBean为抽象方法,由子类AbstractAdvisorAutoProxyCreator实现
// AbstractAdvisorAutoProxyCreator的实现版本,只针对上下文中实现了Advisor接口的bean
// 该类自身的方法findCandidateAdvisors中使用BeanFactoryAdvisorRetrievalHelper进行切面通知收集
// AnnotationAwareAspectJAutoProxyCreator为实际意义上的最终实现版本,重写了上面的findCandidateAdvisors方法
// 在原本的功能上,扩展使用BeanFactoryAspectJAdvisorsBuilder对上下文所有bd进行遍历
// 收集有@Aspect注解修饰的bean(非ajc编译)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 使用切面通知,创建真正的代理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 添加代理对象类型缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
}
实例化前置处理,构造ProxyFactory来创建代理对象。
getEarlyBeanReference
该方法是用于提前引用的函数接口ObjectFactory#getObject
的具体实现之一。
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
// 获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果earlyProxyReferences缓存不包含该key,则添加key到缓存中
// 这个缓存主要用于postProcessAfterInitialization方法中,
// 避免重复执行方法wrapIfNecessary,对bean进行重复封装
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
// 如有必要,包装给定的bean,即,如果它有资格被代理。
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
postProcessAfterInitialization
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
// 初始化后的bean如果不为null
if (bean != null) {
// 获取key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 其他bean注入字段属性时,触发当前bean的实例化,
// 调用getSingleton(String beanName)
// -> ObjectFactory#getObject()
// -> 调用所有bpp的getEarlyBeanReference方法
// bean实例化后,如果允许提前曝光
// (单例 且 允许循环引用 且 该bean正在创建(通过beanFactory调用getType等会标记bean为正在创建) )
// 则直接添加函数接口
// AbstractAutowireCapableBeanFactory#doCreateBean 566
// addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 判断是否执行过代理包装,如存在,则跳过
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
}
wrapIfNecessary
通过上面两个方法源码可知,方法getEarlyBeanReference
和方法postProcessAfterInitialization
实际调用的是方法wrapIfNecessary
对目标源进行代理包装。
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果目标源包含该beanName,则返回bean本身
// 证明已经封装过了(上面方法postProcessBeforeInstantiation中,已创建代理对象)
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 通过缓存校验,是否符合创建代理条件,
// 方法postProcessBeforeInstantiation和当前方法末尾都缓存了该key
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 缓存不存在,则重新判断,方法postProcessBeforeInstantiation有说明
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 如果我们有建议(切面),创建代理。
// 获取所有切面,参考上面postProcessBeforeInstantiation说明
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 切面不为空时,进行代理创建
if (specificInterceptors != DO_NOT_PROXY) {
// 设置缓存,true
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理,上面postProcessBeforeInstantiation方法有createProxy方法的说明
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存bean对应的最终beanClass
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象
return proxy;
}
// 如果执行到这一步,证明上面没有进行代理创建,则设置缓存false,防止重复解析处理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
至此,可知全部方法最终都会通过方法AbstractAutoProxyCreator#createProxy
进行代理对象创建。
createProxy
package org.springframework.aop.framework.autoproxy;
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
// 为给定bean创建AOP代理。
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();
// proxyTargetClass
// 是否直接代理目标类,而不是仅仅代理特定的接口。默认为“false”。
// 将此设置为“true”以强制为TargetSource的公开目标类进行代理。
// 如果目标类是一个接口,则将为给定的接口创建JDK代理。如果目标类是任何其他类,则将为给定的类创建CGLIB代理。
// 注意:根据具体代理工厂的配置,如果没有指定接口(并且没有激活接口自动检测),也将应用proxy-target-class行为。
// optimize
// 代理是否应该执行主动优化。
// “积极优化”的确切含义因代理而异,但通常会有一些权衡。默认为“false”。
// 例如,优化通常意味着在创建代理后通知更改不会生效。
// 因此,优化在默认情况下是禁用的。如果其他设置排除优化,则可能忽略优化值“true”:
// 例如,如果“exposeProxy”设置为“true”,则与优化不兼容。
// exposeProxy
// 代理是否应该由AOP框架作为ThreadLocal公开,以便通过AopContext类进行检索。
// 如果一个被通知的对象需要调用另一个被通知的方法,这是很有用的。
// (如果使用此方法,则不会通知调用)。
// 默认为“false”,以避免不必要的额外拦截。这意味着不能保证AopContext访问将在被建议对象的任何方法中一致地工作。
// frozen
// 是否冻结此配置。当配置被冻结时,不能进行建议更改。
// 这对优化很有用,当我们不希望调用者能够在转换为建议后操纵配置时也很有用。
// opaque
// 设置该配置创建的代理是否禁止强制转换为“建议查询代理状态”。默认值是“false”,
// 这意味着任何AOP代理都可以被强制转换为建议。
// 设置ProxyConfig里的配置属性(当前类继承了ProxyConfig)
proxyFactory.copyFrom(this);
// 当配置为代理目标接口时,需要校验
if (!proxyFactory.isProxyTargetClass()) {
// 确定是否应该用它的目标类而不是接口来代理给定bean。
// 检查相应bd的“preserveTargetClass”属性。
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
// 检查给定bean类上的接口
else {
// 获取bean类所有接口
// 如果接口非配置回调接口
//(InitializingBean/DisposableBean/Closeable/AutoCloseable/Aware)
// 且 非内部语音接口(接口名不等于groovy.lang.GroovyObject,
// 不以.cglib.proxy.Factory或.bytebuddy.MockAccess结尾)
// 且 方法数量大于0
// 符合以上条件则代理目标接口.setProxyTargetClass(false);
// 否则代理目标类.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 确定给定bean的切面通知,包括特定的拦截器和公共拦截器,所有这些都适用于Advisor接口。
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 设置通知
proxyFactory.addAdvisors(advisors);
// 设置目标源
proxyFactory.setTargetSource(targetSource);
// 自定义代理工厂,默认实现为空。
customizeProxyFactory(proxyFactory);
// 指示是否应该冻结代理。重写父类以防止配置过早冻结。
proxyFactory.setFrozen(this.freezeProxy);
// 返回子类返回的advisor是否已经预先过滤以匹配bean的目标类,从而允许在为AOP调用构建advisor链时跳过ClassFilter检查。
// 默认为false。如果子类总是返回预过滤的advisor,那么它们可以覆盖这个。
if (advisorsPreFiltered()) {
// 是否已经为特定的目标类过滤了advisor
proxyFactory.setPreFiltered(true);
}
// 代理工厂创建代理
return proxyFactory.getProxy(getProxyClassLoader());
}
}
AbstractAutoProxyCreator便是实现Spring刷新过程中嵌入自动代理的主要逻辑了,关于上面提到的扩展功能的几个主要的类,按照说明自己跟一下代码其实就会很清楚,实际内容不多,就不贴代码一一说明了。
通过上面的源码走读可以知道,这几个BeanPostProcessor方法最终都是调用了createProxy
方法,即创建一个ProxyFactory
代理工厂,进行实际的代理对象创建。
ProxyFactory
代理工厂和Spring刷新过程的处理逻辑其实关联不大,可以当做一个独立的模块来看待,模块功能为:创建一个灵活的动态代理对象。
接下来就走读代理工厂的源码。
ProxyCreatorSupport
ProxyFactory
工厂用于编程使用的AOP代理,而不是通过bean工厂中的声明性设置。这个类提供了在自定义用户代码中获取和配置AOP代理实例的简单方法。
类图
ProxyFactory只是提供了一些静态方法,方便用户使用,其父类ProxyCreatorSupport才是实现具体的动态代理创建的类。
AbstractAutoProxyCreator#createProxy方法中,最终是构建代理工厂获取代理对象,如下:
return proxyFactory.getProxy(getProxyClassLoader());
对应类中方法为
package org.springframework.aop.framework;
public class ProxyFactory extends ProxyCreatorSupport {
// 根据此工厂中的设置创建一个新的代理。
// 可以反复调用。如果我们添加或删除了接口,效果会有所不同。可以添加和删除拦截器。
// 使用给定的类装入器(如果需要创建代理)。
public Object getProxy(@Nullable ClassLoader classLoader) {
// createAopProxy()为父类方法,返回一个AopProxy对象
// AopProxy为已配置AOP代理的委托接口,允许创建实际的代理对象。
// JDK动态代理和CGLIB代理都有开箱即用的实现,如DefaultAopProxyFactory所应用的那样。
// JDK动态代理 JdkDynamicAopProxy
// CGLIB代理 ObjenesisCglibAopProxy
// AopProxy#getProxy(classLoader) 方法:指定类加载器,返回真正的代理对象。
return createAopProxy().getProxy(classLoader);
}
}
调用父类方法ProxyCreatorSupport#createAopProxy
createAopProxy
package org.springframework.aop.framework;
public class ProxyCreatorSupport extends AdvisedSupport {
// AopProxy工厂,用于创建AopProxy,默认实现为DefaultAopProxyFactory
// AopProxyFactory#createAopProxy方法功能:
// 根据配置ProxyConfig,进行AopProxy对象创建(JdkDynamicAopProxy / ObjenesisCglibAopProxy)
private AopProxyFactory aopProxyFactory;
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
// 子类应该调用它来获得一个新的AOP代理。他们不应该用'this'作为参数来创建AOP代理。
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
// 激活此代理配置。
activate();
}
// 获取AopProxyFactory
// ProxyCreatorSupport类继承了ProxyConfig类
// AopProxyFactory#createAopProxy方法,返回一个委派类AopProxy
return getAopProxyFactory().createAopProxy(this);
}
// 返回这个ProxyConfig使用的AopProxyFactory。
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
}
创建对象时,默认创建了AopProxyFactory对象(DefaultAopProxyFactory),通过AopProxyFactory创建一个代理委派类AopProxy。
DefaultAopProxyFactory
package org.springframework.aop.framework;
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 执行主动优化 或 代理目标类 或 存在非SpringProxy代理接口
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.");
}
// Proxy.isProxyClass(class)
// 当且仅当指定的类使用getProxyClass方法或newProxyInstance方法动态生成为代理类时返回true。
// 此方法的可靠性对于使用它做出安全决策的能力非常重要,因此它的实现不应该仅仅测试所讨论的类是否扩展了Proxy。
// 如果为接口 或 目标类为代理类,则是由jdk动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用Cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
// 默认使用jdk动态代理
else {
return new JdkDynamicAopProxy(config);
}
}
// 确定提供的AdvisedSupport是否只指定了SpringProxy接口(或者根本没有指定代理接口)。
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
上面创建了代理委派对象AopProxy,最后通过调用委派对象方法AopProxy#getProxy获取真正的代理对象。
AopProxy
已配置AOP代理的委托接口,允许创建实际的代理对象。
JDK动态代理和CGLIB代理都有开箱即用的实现,如DefaultAopProxyFactory所应用的那样。
走读JDK动态代理实现
JdkDynamicAopProxy
基于JDK的AopProxy实现,用于Spring AOP框架,基于JDK动态代理。
创建一个动态代理,实现AopProxy公开的接口。动态代理不能用于代理类(而不是接口)中定义的方法。
这种类型的对象应该通过代理工厂获得,由AdvisedSupport类配置。该类位于Spring的AOP框架内部,不需要由客户端代码直接使用。
如果底层(目标)类是线程安全的,那么使用该类创建的代理将是线程安全的。
代理是可序列化的,只要所有的Advisors(包括建议和切入点)和TargetSource是可序列化的。
具体实现逻辑类似上面提到的原理demo
在走读AopProxy代码前,先介绍一些类
Joinpoint
连接点
这个接口表示一个通用的运行时连接点(用AOP术语来说)。
运行时连接点是发生在静态连接点(即程序中的某个位置)上的事件。例如,调用是方法上的运行时连接点(静态连接点)。可以使用getStaticPart()方法一般地检索给定连接点的静态部分。
在拦截框架的上下文中,运行时连接点是对可访问对象(方法、构造函数、字段)的访问的具体化,即连接点的静态部分。它被传递给安装在静态连接点上的拦截器。
核心方法:Object proceed() throws Throwable;
,在spring中表示方法的执行。Invocation
调用连接点
Joinpoint的子接口,该接口表示程序中的调用。调用是一个连接点,可以被拦截器拦截。MethodInvocation
方法调用连接点
Invocation的子接口,对方法调用的描述,在方法调用时给出给拦截器。方法调用是一个连接点,可以被方法拦截器拦截。ProxyMethodInvocation
代理方法调用连接点
MethodInvocation接口的扩展,允许访问方法调用所通过的代理。如果有必要,可以用代理替换返回值,例如调用目标返回自己。
Pointcut
切入点
核心Spring切入点抽象。切入点由一个ClassFilter
和一个MethodMatcher
组成。这些基本术语和切入点本身都可以组合起来构建组合(例如,通过org.springframework.aop.support.ComposablePointcut)。ClassFilter
类过滤器
限制切入点或引入到一组给定目标类的匹配的过滤器。可以用作切入点Pointcut的一部分,也可以用于整个IntrotionAdvisor的目标。MethodMatcher
方法匹配器
切入点的一部分:检查目标方法是否有资格获得通知。
MethodMatcher可以静态计算,也可以在运行时(动态)计算。静态匹配涉及方法和(可能的)方法属性。动态匹配还使特定调用的参数可用,并且运行先前通知的任何效果都应用于连接点。Advice
通知标记
通知的标记接口。实现可以是任何类型的通知,比如拦截器。通俗的说就是用户自定义的切面增强方法。BeforeAdvice
前置通知标记
Advice子接口,用于before通知的通用标记接口,如MethodBeforeAdvice。
Spring目前只支持方法前置通知增强。虽然这不大可能改变,但如果需要,这个API的设计允许在将来提供字段通知(字段级别)。AfterAdvice
后置通知标记
Advice子接口,用于事后通知的通用标记接口,如AfterReturningAdvice和ThrowsAdvice。AfterReturningAdvice
返回通知标记
AfterAdvice子接口,用于返回通知的通用标记接口。
仅在正常方法返回时调用,而不是在抛出异常时调用。这样的通知可以看到返回值,但不能更改它。ThrowsAdvice
异常抛出通知标记
AfterAdvice子接口,用于抛出通知的标记接口。注意:如果throw -advice方法本身抛出异常,它将覆盖原始异常(即更改抛出给用户的异常)。
Interceptor
拦截器
Advice的子接口,表示一个泛型拦截器。通用拦截器可以拦截在基本程序中发生的运行时事件。这些事件通过连接点具体化(具体化)。运行时连接点可以是调用、字段访问、异常……MethodInterceptor
方法拦截器
Interceptor
子接口,函数式接口(@FunctionalInterface)
,在接口到目标的途中拦截接口上的调用。它们嵌套在目标的“顶部”。用户应该实现invoke(MethodInvocation)方法来修改原始行为。
Advisor
顾问,通知包装类
基本接口,包含AOP通知Advice(在连接点采取的操作)和决定通知适用性的过滤器(例如切入点Pointcut),该接口仅包含Advice属性,切入点Pointcut属性由子类子接口提供规范。这个接口不是供Spring用户使用的,而是为了支持不同类型通知的通用性。
Spring AOP基于通过方法拦截传递的通知,符合AOP联盟拦截API。Advisor接口允许支持不同类型的通知,例如前通知和后通知,这些通知不需要使用拦截来实现。PointcutAdvisor
切入点顾问,包装:通知+切入点
由切入点Pointcut驱动的所有Advisor的超接口。这涵盖了几乎所有的Advisor,除了介绍Advisor(IntroductionAdvisor,其不适用方法级匹配)。IntroductionAdvisor
引入顾问,包装:通知+类过滤器
可以在不改动目标类定义的情况下,为目标类增加新的属性和行为。针对的是一个类,并且通知需要实现具体引入的接口。
InterceptorAndDynamicMethodMatcher
拦截链元素类
内部框架类,将MethodInterceptor
实例与MethodMatcher
结合起来,用作Advisor链中的元素。
方法的所有增强通知,会包装成该类作为执行链的元素。
AopProxy 接口实现
package org.springframework.aop.framework;
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
@Override
public Object getProxy() {
// 不指定类加载器,则使用默认类加载器
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
// 确定要为给定AOP配置代理的完整接口集。
// 这将始终添加被建议的接口,除非AdvisedSupport的"opaque"标志是打开的。
// 总是添加SpringProxy标记接口。
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 查找可能在提供的接口集上定义的任何等号或hashCode方法。
// 存在则设置对应标记equalsDefined和hashCodeDefined为true
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 跟了这么久,终于到了真正使用JDK动态代理了
// Proxy.newProxyInstance(ClassLoader loader,
// Class<?>[] interfaces,
// InvocationHandler h);
// ClassLoader loader->classLoader 指定类加载器
// Class<?>[] interfaces->proxiedInterfaces 要代理的接口集合
// InvocationHandler h->this 当前类继承了InvocationHandler
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
}
InvocationHandler.invoke 接口实现
package org.springframework.aop.framework;
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// MethodInvocation
// 对方法调用的描述,在方法调用时给出给拦截器。
// 方法调用是一个连接点,可以被方法拦截器拦截。
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// 获取目标源
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 目标没有重写equals(Object)方法 且 执行的是equals(Object)方法 时
// 调用JdkDynamicAopProxy的equals(Object)方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
// 目标本身不实现equals(Object)方法。
return equals(args[0]);
}
// 目标没有重写hashCode()方法 且 执行的是hashCode()方法 时
// 调用JdkDynamicAopProxy的hashCode()方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
// 目标本身不实现hashCode()方法。
return hashCode();
}
// 方法声明类为DecoratingProxy时
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
// 只有getDecoratedClass()声明 -> 分派到代理配置。
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
// 使用代理配置在ProxyConfig上进行服务调用…
// 作为AOP方法调用的一部分,通过反射调用给定的目标 -> method.invoke(this.advised, args)
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 是否需要暴露代理,即将proxy存储到一个ThreadLocal中
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.
// 获取此方法的拦截链。
// BeanPostProcessor已经将所有相关的bean转换成了Advisor:
// ->AbstractAutoProxyCreator#createProxy 463
// ->AbstractAutoProxyCreator#buildAdvisors
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.
// 看看我们是否有什么建议。如果我们不这样做,我们可以退回到对目标的直接反射调用,
// 并避免创建MethodInvocation。
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.
// 我们可以跳过创建MethodInvocation:直接调用目标
// 注意,最后的调用者必须是一个InvokerInterceptor,
// 这样我们就知道它除了对目标执行反射操作之外什么也不做,并且没有热插拔或花哨的代理。
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// ----------------------------------------------------
// ------------------ 重点 -----------------------------
// ----------------------------------------------------
// We need to create a method invocation...
// 我们需要创建一个方法调用…
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.
// 特殊情况:它返回"this"并且该方法的返回类型是类型兼容的。
// 注意,如果目标在另一个返回对象中设置了对自身的引用,我们也无能为力。
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。
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
// 恢复旧代理。
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
上面的
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
为主要的切面增强执行实现,将所有通知增强构造成一个拦截链,然后一个一个节点执行,参考上面demo。
看一下这个类的代码:
ReflectiveMethodInvocation
package org.springframework.aop.framework;
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
// 需要动态检查的MethodInterceptor和InterceptorAndDynamicMethodMatcher的列表。
protected final List<?> interceptorsAndDynamicMethodMatchers;
// 我们正在调用的当前拦截器从0开始的索引。
// 默认-1,表示当前拦截器
private int currentInterceptorIndex = -1;
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 我们从索引-1开始,并尽早增加。
// 拦截链为空 或者 拦截链已执行完毕
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 使用反射调用连接点。子类可以覆盖它以使用自定义调用。
// AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
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.
// 在这里计算动态方法matcher:静态部分将已经被计算并找到匹配。
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 如果符合条件,则执行该拦截器
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
// 拦截器执行interceptor.invoke(this)
// 入参'this'为一个MethodInvocation
// 拦截器实现会根据不同通知,在合适的地方执行MethodInvocation#proceed()
// 即实现了递归调用当前方法的逻辑。
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 动态匹配失败。
// 跳过这个拦截器,调用链中的下一个拦截器。
// 递归调用当前本法
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 它是一个拦截器,所以我们仅仅只是调用它:在构造这个对象之前,切入点将被静态地求值。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
}
拦截器是Advice的子类,实际上就代表一个通知,接下来看一下不同通知的具体实现。
MethodBeforeAdviceInterceptor 前置拦截器
拦截器来包装MethodBeforeAdvice。由AOP框架内部使用;应用程序开发人员不需要直接使用这个类。
package org.springframework.aop.framework.adapter;
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
// 拦截器对应的通知增强方法对象
private final MethodBeforeAdvice advice;
// 为给定的通知创建一个新的MethodBeforeAdviceInterceptor。
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();
}
}
拦截器与具体的通知增强方法是分离。
AspectJMethodBeforeAdvice
封装了AspectJ before方法的Spring AOP通知。
类结构
主要代码
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
// 执行通知增强方法
// 该方法为父类AbstractAspectJAdvice的方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
AspectJAfterAdvice 后置拦截器
在通知方法之后包装AspectJ的Spring AOP通知。
类结构
主要代码
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行方法连接点
return mi.proceed();
}
finally {
// 通过这里可以知道,后置通知无论是否抛出异常,都会执行
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
}
拦截器和通知增强方法是合并的,AspectJAfterAdvice
既是拦截器,也是通知增强方法本身。
AfterReturningAdviceInterceptor 后置返回拦截器
拦截器来包装一个afterreturnningadvice。由AOP框架内部使用;应用程序开发人员不需要直接使用这个类。
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
// 拦截器对应的通知增强方法对象
private final AfterReturningAdvice advice;
// 为给定的通知创建一个新的AfterReturningAdviceInterceptor。
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;
}
}
拦截器与具体的通知增强方法是分离。
AspectJAfterReturningAdvice
Spring AOP通知包装了一个AspectJ后返回通知方法。
类结构
主要代码
package org.springframework.aop.aspectj;
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
implements AfterReturningAdvice, AfterAdvice, Serializable {
@Override
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
// shouldInvokeOnReturnValueOf方法:
// 按照AspectJ语义,如果指定了返回子句,
// 那么只有当返回值是给定返回类型的实例并且泛型类型参数(如果有的话)符合赋值规则时才调用通知。
// 如果返回类型是Object,则通知*总是*被调用。
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}
}
ThrowsAdviceInterceptor 异常抛出拦截器①
注释
拦截器,用于包装抛出后通知。
在ThrowwsAdvice
实现方法参数上的处理程序方法的签名必须是这样的形式:
void afterThrowing([Method, args, target], ThrowableSubclass);
只最后一个参数是必需的。
一些有效方法的例子如下:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
这是一个Spring用户不需要直接使用的框架类。
这个拦截器的作用:用户自定义了实现ThrowwsAdvice
接口,并按照上面类注释编写了afterThrowing方法,spring则会使用适配器ThrowsAdviceAdapter
封装该bean,并注册到拦截器中。
package org.springframework.aop.framework.adapter;
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {
private static final String AFTER_THROWING = "afterThrowing";
// 拦截器对应的通知增强对象
private final Object throwsAdvice;
// 方法抛出通知,由异常类指定
// 对应每个异常,都有单独方法处理
private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<>();
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(Exception ex) 、 afterThrowing(RemoteException)等
// 且
// ( afterThrowing([Method, args, target], ThrowableSubclass) 或 afterThrowing(ThrowableSubclass) )
if (method.getName().equals(AFTER_THROWING) &&
(method.getParameterCount() == 1 || method.getParameterCount() == 4)) {
Class<?> throwableParam = method.getParameterTypes()[method.getParameterCount() - 1];
if (Throwable.class.isAssignableFrom(throwableParam)) {
// An exception handler to register...
// 注册对应异常处理器
this.exceptionHandlerMap.put(throwableParam, method);
if (logger.isDebugEnabled()) {
logger.debug("Found exception handler method on throws advice: " + method);
}
}
}
}
if (this.exceptionHandlerMap.isEmpty()) {
throw new IllegalArgumentException(
"At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");
}
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行方法连接点
return mi.proceed();
}
catch (Throwable ex) {
// 获取异常处理器
Method handlerMethod = getExceptionHandler(ex);
// 异常处理器不为空,则执行抛出通知增强方法
if (handlerMethod != null) {
// 如果该方法抛出异常,会覆盖原异常ex
// 通过反射执行处理器
invokeHandlerMethod(mi, ex, handlerMethod);
}
// 抛出原异常
throw ex;
}
}
}
拦截器与具体的通知增强方法是分离。通知增强方法只要按照约定自定义bean即可(ThrowsAdvice实现类)。
上面是处理用户自定义ThrowsAdvice实现类bean的通知处理,对于注解@AfterThrowing,则是另外一个类AspectJAfterThrowingAdvice
进行处理。
AspectJAfterThrowingAdvice 异常抛出拦截器②
Spring AOP通知包装了一个AspectJ抛出后通知方法。
该类和上面的逻辑基本相同的。
代码
package org.springframework.aop.aspectj;
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行方法连接点
return mi.proceed();
}
catch (Throwable ex) {
// 在AspectJ语义中,在抛出之后,只有当抛出的异常是给定抛出类型的子类型时,
// 才调用指定抛出子句的建议。
// 注解@AfterThrowing修饰方法的Exception是否匹配当前ex
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
}
到这,代码基本走读完了。
。。。。写得好累,懒得总结了,迟点总结。。。。。