Spring AOP 源码走读

Spring版本

Version 5.0.8.RELEASE

官方文档

spring-framework-reference/aop

用法

添加依赖

引入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;
		}
	}

}

到这,代码基本走读完了。

。。。。写得好累,懒得总结了,迟点总结。。。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值