首页 > 编程学习 > 【Spring - AOP】 --- 目标对象增强核心源码解读

文章目录

  • 1 简单回顾
  • 2 spring-aop目标对象的创建和初始化过程概述
  • 3 spring-aop目标对象的后置增强 --- AOP核心原理
    • 3.1 spring-aop目标对象的后置增强入口
    • 3.2 spring-aop目标对象后置增强核心源码解读
    • 3.3 spring-aop目标对象后置增强核心源码读后总结
    • 3.4 简单看一下被增强后的目标对象


1 简单回顾

上篇文章《【Spring - AOP】— AOP核心后置处理器internalAutoProxyCreator的创建过程》讲解了spring - aop的核心后置处理器internalAutoProxyCreator的注册、创建和初始化过程,可以总结如下:

(1)internalAutoProxyCreator通过import注解+实现ImportBeanDefinitionRegistrar接口的方式将其定义注册到注册中心;
(2)internalAutoProxyCreator的注册(或者说定义)时机在BeanPostProcessor创建+初始化之前;
(3)和其他普通单实例bean的创建+初始化一样调用getBean() —> doGetBean() 等方法完成创建和初始化。

上篇文章还讲到spring-aop的核心原理其实就是:在目标业务bean创建+初始化过程中spring利用动态代理机制对原始的业务bean进行增强。本篇文章将主要来探索一下,spring是如何借助后置处理器internalAutoProxyCreator在目标bean的创建过程中对其进行增强的。


2 spring-aop目标对象的创建和初始化过程概述

spring-aop目标对象的创建和初始化过程和其他业务bean的创建和初始化过程基本一致,主要区别在于目标对象创建时,其·前置处理方法不像其他业务bean的创建+初始化一样在AbstractAutowireCapableBeanFactory类中的initializeBean方法里,如下图:
在这里插入图片描述
spring-aop目标方法的前置处理方法其实在AbstractAutowireCapableBeanFactory类中createBean方法中,该方法其实在bean的创建(doCreateBean方法)之前。下面代码为目标对象前置处理方法具体实现的入口,但是一般情况下,这块代码获得的bean总是为null,即前置方法一般不会做什么 — 更具体的这里不做深究。

try { //对应源码485行
	// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
	Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	if (bean != null) {
		return bean;
	}
}

3 spring-aop目标对象的后置增强 — AOP核心原理

3.1 spring-aop目标对象的后置增强入口

spring-aop目标对象的前置处理不在AbstractAutowireCapableBeanFactory类中的initializeBean方法里,但后置处理却在,spring利用动态代理机制对原始的业务bean进行增强逻辑的作用时机正是initializeBean方法中的如下语句块里:

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

跟进上面的方法,通过打断点可以看到getBeanPostProcessors()里有spring-aop的核心后置处理器。
在这里插入图片描述
接下来将接着看一下它是如何对我定义的业务bean进行增强的。


3.2 spring-aop目标对象后置增强核心源码解读

(1)通过断点跟进spring-aop的 后置处理源码所在类AbstractAutoProxyCreator

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		//从缓存中拿到目标bean --- 由于目标bean在执行初始化方法之前已经被创建了,所以肯定可以拿到
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		//如果之前没对该目标bean创建过代理则包装该bean -> 也就是通过动态代理对该bean进行增强
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

(2) 对spring-aop目标类进行增强的核心骨架代码 — wrapIfNecessary方法

该方法里最核心的代码如下:
所在类AbstractAutoProxyCreator

// 获取当前bean对应的通知 或者说拦截器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//如果当前bean需要被代理,则创建代理对象
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;
}

(3)继续跟一下获取当前bean对应的通知的方法getAdvicesAndAdvisorsForBean(),可以找到获取通知的骨架代码如下:

所在类AbstractAdvisorAutoProxyCreator

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//找到所有的通知方法 ---> 拿到有Aspect注解的类,对其进行解析并获得所有的通知方法
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//找到所有适用于本对象的通知方法
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors); //应该是对通知进行扩展---这里不细究了
		//如果适用于本对象的通知不为空的话,对各个通知方法进行排序
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

跟一下断点可以看到 通知排序后的先后顺序为:AfterThrowing -> AfterReturning -> After -> Around -> Before
在这里插入图片描述

(4)接着跟(2)中拿着获取到的通知对当前对象进行代理增强,并返回增强后的代理对象的方法createProxy()

所在类AbstractAutoProxyCreator

	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 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());
	}

(5)真正对当前对象进行代理增强的方法,代码如下:

所在类DefaultAopProxyFactory

@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.");
		}
		//如果目标对象实现了接口或者说指定了使用JDK的动态代理的话,调用JDK动态代理进行目标对象的增强
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		//否则调用CGLIB进行目标对象的增强----一般都会走这个方法进行对象的增强
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

其实可以想像的到config里肯定封装了当前类和适用于当前类对象的所有通知,这里简单看一下:
在这里插入图片描述

3.3 spring-aop目标对象后置增强核心源码读后总结

3.2已经对spring利用动态代理机制对原始的业务bean进行增强的核心源代码进行了解读,但是总感觉乱乱的,这里用图稍作整理,希望以后用到时能让自己快速回忆起来。
在这里插入图片描述

3.4 简单看一下被增强后的目标对象

spring-aop在目标对象的创建+初始化过程中对其进行了代理增强,之后被注入到IOC容器的将也不是目标对象本身了,而是被增强后的目标对象 — 或者直接可以说是目标对象的代理对象。

当然之后再从IOC容器里取目标对象,取到的也将是被增强后的代理对象,而不是目标对象本身,如下图所示:
在这里插入图片描述

Copyright © 2010-2022 ngui.cc 版权所有 |关于我们| 联系方式| 豫B2-20100000