Spring AOP的大致流程
我們?cè)谥暗?章中,知曉了Spring AOP
在BeanPostProcessor
的幾個(gè)關(guān)鍵接口做了介入,分為幾個(gè)關(guān)鍵點(diǎn):
- 將切面類進(jìn)行解析成
advisors
,其中包括解析XML
和被@Aspect
注解標(biāo)注的Java切面類. - 在初始化Bean的階段,將
advisors
對(duì)當(dāng)前Bean
進(jìn)行篩選垮斯,獲取到當(dāng)前Bean
匹配的advisors
. - 進(jìn)行動(dòng)態(tài)代理類的創(chuàng)建.
今天早处,我們就來(lái)看看動(dòng)態(tài)代理類在Spring AOP中是怎樣去創(chuàng)建出來(lái)的.
創(chuàng)建動(dòng)態(tài)代理的入口:wrapIfNecessary
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// beanName不為空,并且存在于targetSourcedBeans中,也就是自定義的TargetSource被解析過(guò)了
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果Bean為advisedBeans撞蚕,也不需要被代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// isInfrastructureClass和shouldSkip的作用:
// 識(shí)別切面類验庙,加載切面類成advisors
// 為什么又執(zhí)行一次是因?yàn)榇嬖谘h(huán)依賴的情況下無(wú)法加載advisor
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 返回匹配當(dāng)前Bean的所有Advice顶吮、Advisor、Interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 創(chuàng)建Bean對(duì)應(yīng)的代理粪薛,SingletonTargetSource用于封裝實(shí)現(xiàn)類的信息
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 下次代理的時(shí)候直接從緩存拿出判斷悴了,不需要重復(fù)代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
targetSourcedBeans
存儲(chǔ)了用戶自定義的targetSource,這部分的bean在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation
中已經(jīng)進(jìn)行了createProxy
的處理违寿,所以在自動(dòng)化代理的環(huán)節(jié)中湃交,要過(guò)濾掉這部分的bean.advisedBeans
存儲(chǔ)了已經(jīng)被Spring AOP處理過(guò)的bean,這部分的bean也是需要進(jìn)行過(guò)濾的.- 進(jìn)行
isInfrastructureClass
和shouldSkip
的處理藤巢,這兩個(gè)方法在之前的文章已經(jīng)做了詳細(xì)的解析搞莺,它們的主要作用是:識(shí)別切面類、解析切面類掂咒。之所以再重復(fù)調(diào)用一次才沧,是為了收尾的工作.getAdvicesAndAdvisorsForBean
獲取當(dāng)前bean匹配的advisors.- 將當(dāng)前bean緩存到
advisedBeans
,創(chuàng)建動(dòng)態(tài)代理-createProxy
,緩存proxyType
. 這里無(wú)論是否能獲取到bean的advisors迈喉,都會(huì)做緩存到advisedBeans
的步驟.已確保不重復(fù)處理同一個(gè)bean.
創(chuàng)建動(dòng)態(tài)代理:createProxy
- org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
// 如果beanFactory是ConfigurableListableBeanFactory的類型,暴露目標(biāo)類
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 創(chuàng)建一個(gè)ProxyFactory,當(dāng)前ProxyCreator在創(chuàng)建代理時(shí),將需要用到的字段賦值到ProxyFactory中去
ProxyFactory proxyFactory = new ProxyFactory();
// 將當(dāng)前的AnnotationAwareAspectJAutoProxyCreator對(duì)象的屬性賦值給ProxyFactory對(duì)象
// 加載一些ProxyConfig
proxyFactory.copyFrom(this);
// 處理proxyTargetClass屬性
// 如果希望使用CGLIB進(jìn)行代理温圆,配置proxyTargetClass為true
if (!proxyFactory.isProxyTargetClass()) {
// 檢查相應(yīng)BeanDefinition的“ preserveTargetClass”屬性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 1. 有接口的挨摸,調(diào)用一次或者多次:proxyFactory.addInterface(ifc);
// 2. 沒(méi)有接口的,調(diào)用: proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 這個(gè)方法主要是對(duì)前面?zhèn)鬟f進(jìn)來(lái)的橫切邏輯實(shí)例進(jìn)行包裝
// specificInterceptors中有Advice和Interceptor,它們都會(huì)被包裝成Advisor
// 調(diào)用的先后順序岁歉,通過(guò)方法中的applyCommonInterceptorsFirst參數(shù)進(jìn)行設(shè)置
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 擴(kuò)展實(shí)現(xiàn)得运,子類可以定制proxyFactory
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 設(shè)置preFiltered的屬性值,默認(rèn)為false.子類:AbstractAdvisorAutoProxyCreator修改為true
// preFiltered字段的意思是:是否為特定目標(biāo)類篩選Advisor
// 該字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice獲取所有的Advisors
// CglibAopProxy和JdkDynamicAopProxy都會(huì)調(diào)用此方法,然后遞歸執(zhí)行所有的advisor
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
- 如果當(dāng)前的beanFactory屬于
ConfigurableListableBeanFactory
類型,給當(dāng)前bean對(duì)應(yīng)的BeanDefinition設(shè)置上屬性"originalTargetClass"為targetClass.- 先new一個(gè)
ProxyFactory
實(shí)例锅移,并根據(jù)AnnotationAwareAspectJAutoProxyCreator
的配置進(jìn)行proxyTargetClass
澈圈、optimize
、exposeProxy
帆啃、frozen
瞬女、opaque
的屬性設(shè)置.- Spring不僅提供了對(duì)所有bean生效的
proxyTargetClass
設(shè)置,也提供了對(duì)單個(gè)bean的動(dòng)態(tài)代理配置preserveTargetClass
.- 調(diào)用buildAdvisors對(duì)
specificInterceptors
進(jìn)行適配努潘,封裝成advisor.有興趣的可以看看org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap
.- 配置
advisors
诽偷、targetSource
、frozen
等屬性后,進(jìn)行動(dòng)態(tài)代理的創(chuàng)建.proxyFactory.getProxy(getProxyClassLoader())
,進(jìn)行動(dòng)態(tài)代理生成.
getProxy: 根據(jù)當(dāng)前bean選擇JDK或者CGLIB動(dòng)態(tài)代理
- org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
// 首先獲取AopProxy對(duì)象疯坤,其主要有兩個(gè)實(shí)現(xiàn):JdkDynamicAopProxy和ObjenesisCglibAopProxy
// 分別用于JDK和CGLIB代理類的生成报慕,其getProxy方法則用于獲取具體的代理對(duì)象
return createAopProxy().getProxy(classLoader);
}
ProxyFactory
是ProxyCreatorSupport
的子類,在ProxyCreatorSupport
中有一個(gè)createAopProxy
方法压怠,從這里可以獲取到具體的代理工廠類.
- org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
// 激活A(yù)dvisedSupportListener監(jiān)聽(tīng)器
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
- activate方法主要是用來(lái)激活A(yù)dvisedSupportListener的.
- 重點(diǎn)方法是這個(gè):getAopProxyFactory().createAopProxy(this);其中,
getAopProxyFactory
中存儲(chǔ)了一個(gè)DefaultAopProxyFactory
,它實(shí)現(xiàn)了AopProxyFactory
接口,接口方法createAopProxy
才是真正獲取代理工廠的地方.
- org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
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.");
}
// 如果要代理的類本身就是接口
// 或者它已經(jīng)是JDK的代理類(Proxy子類)
// 使用JDK動(dòng)態(tài)代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用CGLIB動(dòng)態(tài)代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 接口->JDK動(dòng)態(tài)代理
return new JdkDynamicAopProxy(config);
}
}
這里就會(huì)看到我們很熟悉的一個(gè)邏輯:實(shí)現(xiàn)了接口的bean,Spring會(huì)使用JDK動(dòng)態(tài)代理;否則使用CGLIB代理.
工廠模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy
由于篇幅的原因眠冈,我選擇講解JdkDynamicAopProxy
這種模式生成代理的源碼解析.
- org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 獲取完整的代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// JdkDynamicAopProxy本身實(shí)現(xiàn)了InvocationHandler接口
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
關(guān)于JDK如何生成動(dòng)態(tài)代理的原理,這里不做過(guò)多的分析了菌瘫,這在我之前的博客中有關(guān)于JDK和CGLIB生成Proxy的文章蜗顽,不了解的讀者可以去看看:
點(diǎn)我前往
在生成代理之后,Proxy就會(huì)調(diào)用InvocationHandler.invoke
方法雨让,所以關(guān)于Spring AOP的代理攔截鏈執(zhí)行流程雇盖,我們直接去到invoke
解析即可。
- org.springframework.aop.framework.JdkDynamicAopProxy#invoke
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler
首先,JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler接口,動(dòng)態(tài)代理類最終會(huì)執(zhí)行
InvocationHandler.invoke.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// equals方法不需要代理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// hashcode方法不需要代理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// 如果當(dāng)前方法是Spring織入的DecoratingProxy接口中的方法栖忠,返回目標(biāo)對(duì)象的class類型
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 如果被代理的對(duì)象本身實(shí)現(xiàn)了Advised接口崔挖,則證明該類里面的方法已經(jīng)被代理了,直接執(zhí)行即可
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 是否暴露代理引用
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.
// 獲取目標(biāo)類
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 獲取方法的攔截鏈
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.
// 如果該方法上沒(méi)有匹配的攔截器庵寞,直接反射調(diào)用Method.invoke(target,args)
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 創(chuàng)建ReflectiveMethodInvocation
MethodInvocation 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.
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.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
- Spring AOP不對(duì)equals和hashCode做代理.
- 如果當(dāng)前方法是Spring織入的DecoratingProxy接口中的方法狸相,返回目標(biāo)對(duì)象的class類型.
- 如果被代理的對(duì)象本身實(shí)現(xiàn)了Advised接口,則證明該類里面的方法已經(jīng)被代理了捐川,直接執(zhí)行即可
- 查看當(dāng)前配置判斷是否暴露代理引用脓鹃,可以來(lái)解決this調(diào)用引起的代理失效等問(wèn)題.
- 從targetSource中獲取target信息.獲取當(dāng)前method的攔截鏈路.
getInterceptorsAndDynamicInterceptionAdvice
會(huì)對(duì)method的攔截鏈進(jìn)行緩存,如果沒(méi)有緩存属拾,會(huì)執(zhí)行org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
重新對(duì)method進(jìn)行match.- 從
getInterceptorsAndDynamicInterceptionAdvice
獲取到chain之后,如果chain為空将谊,那么直接激活method.- 如果chain不為空,生成
ReflectiveMethodInvocation
,從JavaDoc可以知道,這是一個(gè)Spring實(shí)現(xiàn)了AOP Alliance MethodInvocation
接口的類渐白,關(guān)鍵方法:invokeJoinpoint
(激活連接點(diǎn)方法)尊浓、proceed
(執(zhí)行攔截鏈邏輯).- 執(zhí)行proceed.
- 處理返回值。包裝此返回值(如果有必要作為代理)纯衍,并驗(yàn)證沒(méi)有將null作為原語(yǔ)返回栋齿。這是什么意思呢:假設(shè)方法返回的是int,增強(qiáng)around方法返回了null,這就會(huì)報(bào)錯(cuò),因?yàn)榛A(chǔ)數(shù)據(jù)類型都有默認(rèn)值.
- 釋放資源、重新設(shè)置一次代理引用.
這里最關(guān)鍵的的看chain的執(zhí)行過(guò)程襟诸,整個(gè)Spring AOP攔截鏈執(zhí)行的過(guò)程采用了一種遞歸的方式瓦堵,值得一品.
代理類執(zhí)行鏈路
- org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 如果攔截器執(zhí)行完了,則執(zhí)行連接點(diǎn)
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 從0開(kāi)始執(zhí)行,每次遞歸進(jìn)來(lái)都會(huì)+1
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.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 動(dòng)態(tài)匹配:運(yùn)行時(shí)參數(shù)是否滿足匹配條件
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 動(dòng)態(tài)匹配失敗歌亲,進(jìn)入下一個(gè)攔截器
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 執(zhí)行當(dāng)前攔截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
- 在遇到
AfterThrowing
菇用、AfterRetruning
、After
這類advice的時(shí)候陷揪,它們會(huì)執(zhí)行mi.proceed
回到chain中.- 回到chain中后惋鸥,列表索引自增,往下執(zhí)行下一個(gè)advice.
- 依次遞歸悍缠,直到遇到
Around
通知卦绣,執(zhí)行around.- 在around中執(zhí)行
joinPoint.proceed
又會(huì)回到chain中.- 遞歸到
Before
,執(zhí)行before
,然后回到around的后置代碼塊中
.- 回溯到
after
、afterReturning
,如果有異常飞蚓,執(zhí)行afterThrowing
.
執(zhí)行流程圖
總結(jié)
- 1. 生成代理類通過(guò)工廠模式進(jìn)行生成,實(shí)現(xiàn)接口默認(rèn)使用JDK動(dòng)態(tài)代理滤港,否則使用CGLIB
- 2. Spring AOP通過(guò)后置處理器的
postProcessAfterInitialization
方法調(diào)用wrapIfNessary
對(duì)Bean進(jìn)行代理并替換. - 3. 代理類執(zhí)行攔截鏈通過(guò)chain進(jìn)行遞歸proceed來(lái)執(zhí)行每個(gè)通知的方法