完整流程
简略版
主线脉络:BeanPostProcessor -> target Object -> Proxy Object -> intercept target method
1.注册BeanProcessor:无论是通过xml还是注解方式启动Spring AOP,在启动过程中,都会注册一个xxxAutoProxyCreator后置处理器。后置处理器可以在目标对象的init-method前后执行某个方法
2.创建目标对象:过程是依次执行 构造方法 -> 设置属性 -> postProcessBeforeInitialization -> afterPropertiesSet -> init-method -> postProcessAfterInitialization
3.在执行postProcessAfterInitialization时,第1步注册的后置处理器就会获取当前对象匹配的所有增强器,如果匹配不到,直接返回;匹配到就进入创建代理对象
4.创建代理对象:过程是依次执行 获取增强器 -> Proxy Factory -> Aop Proxy -> proxy object。获取到的增强器会注入到代理工厂,代理工厂会根据proxyTargetClass属性值、目标类是否实现接口决定使用jdk还是cglib动态代理
5.拦截目标方法:当执行目标方法时,如果是jdk动态代理,会进入到JdkDynamicAopProxy#invoke方法,如果是cglib动态代理,会进入到CglibAopProxy#intercept方法,无论进入哪个方法,处理过程几乎一致。先获取目标方法上的拦截器链,如果为空,直接执行目标方法;非空,则创建MehotdInvocation对象,并调用proceed方法。
6.执行proceed:MehotdInvocation有一个属性用于记录当前拦截器的索引,如果发现索引等于拦截器数量-1,说明全部拦截器都执行完成,需要执行连接点方法。如果
不满足条件,通过索引从拦截器列表获取对应的拦截器,执行其invoke方法
7.拦截器的invoke:每个拦截器实现的invoke方法内容都不同,但是相同点是在invoke最后,继续调用methodInvocation#proceed,重复第6步,直到所有拦截器执行完成
完整版
ioc容器启动流程:
1)、传入配置类,或者指定配置文件,创建ioc容器
2)、注册配置类,调用refresh(),刷新容器;
3)、registerBeanPostProcessors(beanFactory),注册bean的后置处理器来方便拦截bean的创建;
1)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
2)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
3)、最后注册没实现优先级接口的BeanPostProcessor;
4)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
1)、创建Bean的实例
2)、populateBean;给bean的各种属性赋值
3)、initializeBean:初始化bean;
1)、invokeAwareMethods():处理Aware接口的方法回调
2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
3)、invokeInitMethods();执行自定义的初始化方法
4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
5)、把BeanPostProcessor注册到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);
=======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程====
==============以下对象实例创建过程细节==================================
创建代理对象,可看成分为两步:先创建目标对象,再创建代理对象
创建目标对象:
4)、finishBeanFactoryInitialization(beanFactory); 完成BeanFactory初始化工作;创建剩下的单实例bean
1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
getBean->doGetBean()->getSingleton()->
2)、创建bean
1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
2)、createBean(); 创建bean;
创建过程:执行构造函数 -> 属性设置 -> 各种xxxAware接口 -> postProcessBeforeInitialization -> afterPropertySet -> init-method -> postProcessAfterInitialization
--------------------------------------
创建代理对象
1)、init-method执行前,调用postProcessBeforeInstantiation();
不做任何处理(spring 5.1.x)
2)、init-method执行后,调用postProcessAfterInitialization();
1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
1、找到候选的所有的增强器(增强器:哪些通知方法是需要切入当前bean方法的)
2、获取到能在bean使用的增强器。
3、给增强器排序
2)、保存当前bean在advisedBeans中;
3)、如果当前bean需要增强,创建当前bean的代理对象;
1)、获取所有增强器(通知方法)
2)、保存到proxyFactory
3)、创建代理对象:Spring自动决定
JdkDynamicAopProxy(config);jdk动态代理;
ObjenesisCglibAopProxy(config);cglib的动态代理;
4)、给容器中返回当前组件使用cglib增强了的代理对象;
5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
======以下是目标方法的执行==============================================
3)、目标方法执行;容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
1)、CglibAopProxy.intercept();拦截目标方法的执行
2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
1)、List<Object> interceptorList保存所有拦截器 5个
一个默认的ExposeInvocationInterceptor 和 4个增强器;
2)、遍历所有的增强器,将其转为Interceptor;
registry.getInterceptors(advisor);
3)、将增强器转为List<MethodInterceptor>;
如果是MethodInterceptor,直接加入到集合中
如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;
3)、如果没有拦截器链,直接执行目标方法;
4)、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象,
并调用 Object retVal = mi.proceed();
5)、拦截器链的触发过程;
1)、如果没有拦截器则直接执行目标方法,或者 拦截器的索引 和 拦截器数组长度-1 大小一样(指定到了最后一个拦截器)就直接执行目标方法;
2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
拦截器链的机制,保证通知方法与目标方法的执行顺序;
注册后置处理器
我们可以通过@EnableAspectJAutoProxy
开启spring aop功能,启动自动代理。从这个注解入手,看看它做了什么事情。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
可以看到,EnableAspectJAutoProxy有个@Import
注解,导入一个AspectJAutoProxyRegistrar类,继续往下追踪
跟踪到AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary
,可以看到确实是注册AnnotationAwareAspectJAutoProxyCreator类的Bean信息
AnnotationAwareAspectJAutoProxyCreator到底是啥呢??观察它的继承结构体系,我们发现它实现了BeanPostProcessor接口,因此它是一个后置处理器。我们都知道,BeanPostProcessor有两个方法,分别在实例对象的init-method
方法前后执行。
既然我们知道了AnnotationAwareAspectJAutoProxyCreator是个后置处理器,那它在什么时候注册呢??(注册时机)
通过仔细查找,在AbstractApplicationContext#refresh
方法看到调用registerBeanPostProcessors方法,应该就在这里注册所有的后置处理器。
一路追踪,找到PostProcessorRegistrationDelegate#registerBeanPostProcessors
方法,里面代码很多,主要的意思是,按照实现PriorityOrdered、Ordered接口,没实现接口 的顺序依次注册后置处理器。
我们再回看上面的继承结构,发现AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,打个断点,看下啥情况。
可以清晰看到,此时只有一个实现ordered
接口的后置处理器,那应该就是 AnnotationAwareAspectJAutoProxyCreator。怎么确认呢?对比它们的beanName就可以了。来,我们去找下AnnotationAwareAspectJAutoProxyCreator的beanName
我们刚刚已经定位到**@EnableAspectJAutoProxy会在AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary
注册后置处理器,继续往里面跟踪,最终在AopConfigUtils#registerOrEscalateApcAsRequired
找到AnnotationAwareAspectJAutoProxyCreator的beanName**。
两个beanName匹配上了,所以可以确定,@EnableAspectJAutoProxy会在ioc容器启动时,注册一个xxxAutoProxyCreator后置处理器,在bean对象初始化方法执行前后拦截,进行某些操作,最终实现自动代理。
ioc容器启动流程:
1)、传入配置类,或者指定配置文件,创建ioc容器
2)、注册配置类,调用refresh(),刷新容器;
3)、registerBeanPostProcessors(beanFactory),注册bean的后置处理器来方便拦截bean的创建;
1)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
2)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
3)、最后注册没实现优先级接口的BeanPostProcessor;
4)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
1)、创建Bean的实例
2)、populateBean;给bean的各种属性赋值
3)、initializeBean:初始化bean;
1)、invokeAwareMethods():处理Aware接口的方法回调
2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
3)、invokeInitMethods();执行自定义的初始化方法
4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
5)、把BeanPostProcessor注册到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);
创建代理对象
问题:spring aop在什么时候创建代理对象?
Spring AOP配置
我们定义一个LagouBean
,在它的print
方法执行前调用切面方法。以下是配置
public class LagouBean {
public void print() {
System.out.println("print方法业务逻辑执行");
}
}
<bean id="lagouBean" class="com.lagou.edu.LagouBean"></bean>
<!--aop配置-->
<!--横切逻辑-->
<bean id="logUtils" class="com.lagou.edu.LogUtils"></bean>
<aop:config>
<aop:aspect ref="logUtils">
<aop:before method="beforeMethod" pointcut="execution(public void com.lagou.edu.LagouBean.print())"/>
</aop:aspect>
</aop:config>
public class LogUtils {
public void beforeMethod() {
System.out.println("前置通知");
}
}
创建过程
在获取对象的地方,打一个断点,看下是否已经拿到代理对象。
既然在容器启动过程,已经创建代理对象,那么我们不妨再思考下,根据spring bean的生命周期,哪个方法最合适创建对象??既然需要代理,那前提是有目标对象。我们知道在执行后置处理器的postProcessAfterIntialization()
时,一个完整的对象实例已经创建完成,所以该方法是个合适的创建代理对象时机。
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// getgetBeanPostProcessors():获取到多个后置处理器,我们需要找到与自动代理相关的AbstractAutoProxyCreator
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
由于ioc容器会有多个后置处理器,与Spring AOP相关的是AbstractAutoProxyCreator,继续往下执行,马上就能找到创建对象的方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取该对象匹配的增强器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
在AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
方法中调用findEligibleAdvisors
方法,获取增强器。
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取对象匹配的增强器
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有增强器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 匹配目标类的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 增强器排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
AbstractAutoProxyCreator#createProxy
在这个方法里面,会创建一个代理工厂,进行一些配置
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();
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());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
// 先创建AOP Proxy,再创建Proxy
return createAopProxy().getProxy(classLoader);
}
@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.");
}
// 目标对象是接口,或者目标对象是代理对象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用cglib动态代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用jdk动态代理
return new JdkDynamicAopProxy(config);
}
}
由于LagouBean
没有实现接口,所以通过cglib
创建代理对象,在CglibAopProxy#getProxy
截取部分代码,可以看到使用cglib
创建代理对象。
总结
跟着上面的步骤,我们看到了代理对象的创建过程。在spring启动过程中,首先创建目标对象,目标对象在执行init-method方法前后会被后置处理器拦截,其中AbstractAutoProxyCreator
后置处理器会创建代理对象。过程是先获取目标类匹配到的增强器,接着创建一个代理工厂ProxyFactory
,注入增强器和目标类。接着会根据目标对象是否实现接口、proxyTargetClass
的属性值等判断条件,选择创建JDK
还是CGLIB
动态代理的AopProxy
,最后调用对应的动态代理的方法创建代理代理对象
增强器:我的理解是横切时需要执行的代码和切入时机。
创建代理对象,可看成分为两步:先创建目标对象,再创建代理对象
创建目标对象:
4)、finishBeanFactoryInitialization(beanFactory); 完成BeanFactory初始化工作,创建Bean对象
1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
getBean->doGetBean()->getSingleton()->
2)、创建bean
1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
2)、createBean(); 创建bean;
创建过程:执行构造函数 -> 属性设置 -> 各种xxxAware接口 -> beforeInit -> afterPropertySet -> init-method -> afterInit
--------------------------------------------------------------------------------------------------------------------------
创建代理对象
1)、init-method执行前调用postProcessBeforeInstantiation();
不做任何处理(spring 5.1.x)
2)、init-method执行后调用postProcessAfterInitialization();
1)、获取当前bean的所有增强器(通知方法) Object[] specificInterceptors
1、找到候选的所有的增强器(增强器:找哪些通知方法是需要切入当前bean方法的)
2、获取到能在bean使用的增强器。
3、给增强器排序
2)、保存当前bean在advisedBeans中;
3)、如果当前bean需要增强,创建当前bean的代理对象;
1)、获取所有增强器(通知方法)
2)、保存到proxyFactory
3)、创建代理对象:Spring自动决定
JdkDynamicAopProxy(config);jdk动态代理;
ObjenesisCglibAopProxy(config);cglib的动态代理;
4)、给容器中返回当前组件使用cglib增强了的代理对象;
5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
获取拦截器链
接下来,我们继续分析目标方法被拦截并执行的过程。
因为需要跟踪目标方法执行过程,我们在目标方法处打一个断点,从这里逐步跟踪。
可以看到,此时的bean对象已经是由cglib创建的代理对象,我们一路debug,进入到DynamicAdvisedInterceptor#intercept
方法,且慢,我们再回头看下,刚刚获取到的代理对象其中有个属性CGLIB$CALLBACK_0
的值就是DynamicAdvisedInterceptor
对象。
由于intercept
方法内容比较多,直接说下过程,方法里面会获取目标方法的拦截链,接着创建MethodInvocation对象,并调用proceed方法,触发拦截器。
我们去瞧瞧ReflectiveMethodInvocation#proceed
方法,里面有一个currentInterceptorIndex
记录当前拦截器索引,当所有拦截器都执行完成,就调用连接点。
我们将分多次进入这个方法,更加直观感受这执行过程。。。
第一次进入,执行ExposeInvocationInterceptor#invoke
。另外,我们可以看到interceptorsAndDynamicMethodMatchers 保存了所有拦截器,每次通过当前下标获取对应的拦截器。
第二次进入,执行MethodBeforeAdviceInterceptor#invoke
方法 ,在方法体内,通过methodInvocation,再次调用proceed方法。
第三次进入,执行CglibMethodInvocation#invokeJoinpoint
,一路跟踪,最终执行连接点方法
根据以上的分析,我们可以知道,代理对象执行目标方法时,会被CglibAopProxy.intercept
拦截,(DynamicAdvisedInterceptor是CglibAopProxy内部类)。
在intercept方法中,会获取到目标方法的拦截器链,接着创建一个CglibMethodInvocation
对象,并调用proceed
方法。在proceed方法中,会记录当前拦截器的索引,通过索引从匹配器列表获取到对应拦截器,接着调用拦截器实现的invoke方法,在invoke方法里面,还会继续调用MethodInvocation的proceed方法。再次进入proceed,重复之前的执行过程,直到所有拦截器执行完成,就调用连接点方法。
调用过程:CglibAopProxy.intercept -> methodInvocation -> proceed -> Intercept -> invoke
| _ _ _ _ _ _ _ _ _ _ _ |初始入口:CglibAopProxy.intercept 创建的methodInvocation
循环结束:
currentInterceptorIndex
等于拦截器长度-1
3)、目标方法执行;容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
1)、CglibAopProxy.intercept() ==== 》》》 拦截目标方法的执行
2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
1)、List<Object> interceptorList保存所有拦截器 5个
1个默认的ExposeInvocationInterceptor 和 4个增强器;
2)、遍历所有的增强器,将其转为Interceptor;
registry.getInterceptors(advisor);
3)、将增强器转为List<MethodInterceptor>;
如果是MethodInterceptor,直接加入到集合中
如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
转换完成返回MethodInterceptor数组;
3)、如果没有拦截器链,直接执行目标方法;
4)、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象,
并调用 Object retVal = mi.proceed();
5)、拦截器链的触发过程;
1)、如果没有拦截器则直接执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)就直接执行目标方法;
2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
拦截器链的机制,保证通知方法与目标方法的执行顺序;
补充:刚刚我们使用的是CGLIB动态代理,如果使用JDK动态代理时,执行目标方法,会被
JdkDynamicAopProxy#invoke
拦截,执行过程和CglibAopProxy#intercept
一样,都会先获取拦截器链,接着创建MethodInvocation对象,调用proceed方法。