文章目录
- 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容器里取目标对象,取到的也将是被增强后的代理对象,而不是目标对象本身,如下图所示: