Spring AOP源码

结合 Spring 后置处理器源码Spring Aware源码 ,再来看下 Spring AOP 的源码。

启动 AOP

使用 @EnableAspectJAutoProxy 这个注解来启用 AOP 的能力了。它使用 @Import 导入类 AspectJAutoProxyRegistrar,这个类实现了 ImportBeanDefinitionRegistrar,所以它会被 ConfigurationClassParser 扫描,并加入缓存中。然后 ConfigurationClassBeanDefinitionReader 从缓存中会拿到这个类,再执行其实现的方法 registerBeanDefinitions()。

AspectJAutoProxyRegistrar.registerBeanDefinitions() 源码

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}

上述方法又使用 AOP 配置工具类 AopConfigUtils 将 AnnotationAwareAspectJAutoProxyCreator 也注册到 BeanFactory,其 name 为 org.springframework.aop.config.internalAutoProxyCreator。

下图,展示了 AnnotationAwareAspectJAutoProxyCreator 的类继承关系
AnnotationAwareAspectJAutoProxyCreator

可以看出来 AnnotationAwareAspectJAutoProxyCreator 就是 BeanPostProcessor 和 Aware,其顶层抽象类 AbstractAutoProxyCreator 实现它们的接口。

创建代理对象

Spring Aware源码 中可知,BeanFactoryAware 实现类会在 invokeAwareMethods() 被回调 setBeanFactory() 方法,将 DefaultListableBeanFactory 注入给 AnnotationAwareAspectJAutoProxyCreator。

InstantiationAwareBeanPostProcessor 新增了后置处理器方法 postProcessBeforeInstantiation() 和 postProcessAfterInstantiation(),这两个方法会在 Bean 初始化之前,也就是在 BeanPostProcessor 定义的方法之前先调用。

  • postProcessBeforeInstantiation() 会在反射调用 Bean 的构造器之前调用。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 会返回一个代理对象,会执行 postProcessBeforeInstantiation()
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
	return doCreateBean(beanName, mbdToUse, args);
}
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 从缓存获取
	Object cacheKey = getCacheKey(beanClass, beanName);
	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 判断是否已经在 advisedBeans 缓存
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
		// 判断 Bean 是否是 Advice/Pointcut/Advisor/AopInfrastructureBean 这些不需要代理的基础类型;或者是否 @Aspect 注解类
		// 找到切面类中的所有通知方法,判断是否 AspectJPointcutAdvisor 类型,否则返回 false
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}
	return null;
}
  • postProcessAfterInstantiation() 会在给属性赋值的方法 populateBean() 中执行。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
    // 属性赋值,会执行 postProcessAfterInstantiation()
	populateBean(beanName, mbd, instanceWrapper);
	// 执行 BeanPostProcessor 的方法
	return initializeBean(beanName, exposedObject, mbd);
}
  • BeanPostProcessor 的方法是在 initializeBean() 中才执行的。其中 postProcessAfterInitialization() 方法会获取切面类的所有通知方法,利用动态代理技术,创建增强的代理对象(比如:com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880),同时会设置回调方法,完成后返回。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
		    // 包装
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}
// 包装类
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 找到所有的候选通知方法
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 从候选通知方法找到可用于当前 Bean 的通知
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	// 获取所有的通知拦截器对象
	Object[] specificInterceptors = eligibleAdvisors.toArray();
	// 利用 AopProxy 来创建代理对象
	// AopProxy 包含 JDK 和 CGLib 两种实现
	Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
	return proxy;
}

至此,动态代理对象以及创建完成了,容器中就会有这个增强后的代理对象,方法执行时,也就会利用这个代理对象来执行通知方法了。

执行代理对象

执行被代理的方法时,会被 CglibAopProxy 拦截器拦截,获取这个方法的拦截器链。如果有拦截器链,则创建 CglibMethodInvocation 对象,执行 proceed(),即执行通知方法,最后返回 retVal,即方法的返回值;如果没有拦截器链,则直接执行方法;

拦截器链实际上就是把方法拦截器放在 ArrayList 队列中,第一个默认是 ExposeInvocationInterceptor,剩下的默认顺序为 AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice、AspectJAfterAdvice、AspectJAroundAdvice、AspectJMethodBeforeAdvice。

proceed() 按照上面 ArrayList 中的顺序递归调用,当遇到 AspectJAroundAdvice、AspectJMethodBeforeAdvice 类型的通知时,会利用反射直接执行它们的通知方法,其他类型通知不会立即执行,会等待递归返回之后再行调用 invoke() 方法。这样,就能保证通知和方法的执行顺序:

环绕通知执行 proceed() 前->前置通知->执行方法->环绕通知执行 proceed() 后->后置通知->返回通知->方法返回

总结

  1. @EnableAspectJAutoProxy 使用 @Import(AspectJAutoProxyRegistrar.class) 导入 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar。
  2. 容器刷新时,invokeBeanFactoryPostProcessors() 执行 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar.registerBeanDefinitions() 注册 AnnotationAwareAspectJAutoProxyCreator 到 BeanFactory。
  3. AnnotationAwareAspectJAutoProxyCreator 实现了 InstantiationAwareBeanPostProcessor 和 BeanFactoryAware,在 registerBeanPostProcessors() 将其注册到 BeanFactory,并且执行 invokeAwareMethods() 回调 (AbstractAdvisorAutoProxyCreator)BeanFactoryAware.setBeanFactory() 方法。
  4. finishBeanFactoryInitialization() 执行 (AnnotationAwareAspectJAutoProxyCreator)BeanPostProcessor.postProcessAfterInitialization(),找到切面类及其切面通知方法,使用动态代理技术(ObjenesisCglibAopProxy/JdkDynamicAopProxy),对切面类进行增强,创建增强后的代理对象com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
  5. 执行被代理的方法时,会被 CglibAopProxy 的拦截器拦截,拿到方法的拦截器链,按顺序递归调用,利用反射技术执行通知方法,以此实现不同通知的调用顺序。
posted @ 2019-08-09 00:01  O&#39;Neal  阅读(459)  评论(0编辑  收藏  举报