前言
在上一篇文章中,我們講解了Spring中那些注解可能會產生AOP動態代理,我們通過源碼發現,完成AOP相關操作都和ProxyFactory這個類有密切關系,這一篇我們將圍繞這個類繼續解析
演示
作用
ProxyFactory采用策略模式生成動態代理對象,具體生成cglib動態代理還是jdk動態代理,是根據我們具體設置的內容所決定的,我們分別演示一下生成cglib動態代理和jdk動態代理兩種情況。具體細節可以詳細閱讀DefaultAopProxyFactory的createAopProxy方法
生成cglib動態代理
package com.test.aop.test;public class CglibTarget {public void doObject() {System.out.println("CglibTarget doObject");}
}
package com.test.aop.test;import org.springframework.aop.framework.ProxyFactory;public class CglibProxy {public static void main(String[] args) {ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(new CglibTarget());CglibTarget proxy = (CglibTarget) proxyFactory.getProxy();proxy.doObject();}
}
我們可以發現最終是以cglib動態代理方式生成代理對象
?生成jdk動態代理
package com.test.aop.test;public interface JdkTarget {void doObject();
}
package com.test.aop.test;public class JdkTargetImpl implements JdkTarget {@Overridepublic void doObject() {System.out.println("JdkTargetImpl doObject");}
}
package com.test.aop.test;import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;public class JdkProxy {public static void main(String[] args) {ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setInterfaces(JdkTarget.class);proxyFactory.setTargetSource(new SingletonTargetSource(new JdkTargetImpl()));JdkTarget proxy = (JdkTarget) proxyFactory.getProxy();proxy.doObject();}
}
我們可以發現最終是以jdk動態代理方式生成代理對象?
ProxyFactory源碼解析
我們先觀察一下ProxyFactory這個類的繼承關系
我們以proxyFactory.getProxy()方法為切入口,進行源碼解析?
對上述流程進行梳理,見下圖
我們分別查看兩種方式的代理過程
jdk動態代理過程(JdkDynamicAopProxy)
jdk動態代理的過程比較簡單主要就是利用Proxy.newProxyInstance方法創建代理對象,會默認實現SpringProxy,Advised,DecoratingProxy三個接口
cglib動態代理過程(CglibAopProxy)?
cglib動態代理主要利用我們自定義的ProxyFactory對象,然后根據設置的參數構建Enhancer對象,然后創建代理對象。我們需要注意的是代理對象一共有七個攔截器,spring會根據我們調用的方法,指定攔截器。比如我們調用equal方法就會經過EqualsInterceptor攔截器,調用hashCode方法就會經過HashCodeInterceptor攔截器。我們主要需要關注的就是DynamicAdvisedInterceptor攔截器,除了equal、hashcode這些特殊的方法,普通方法一般都會經過這個攔截器。具體進入那個攔截器可以查看CglibAopProxy類的accept方法
cglib動態代理的對象會默認實現SpringProxy,Advised兩個接口
ProxyFactory的重要屬性Advisor
我們在前文中說到@EnableTransactionManagement,@EnableAspectJAutoProxy完成AOP動態代理都是依靠AbstractAutoProxyCreator的postProcessAfterInitialization方法中完成的,其中最主要的方法是wrapIfNecessary,我們查看相關源碼
通過源碼我們知道只有找到了,可以作用于當前bean的Advisor,spring才會進行動態代理
我們在上文中提到了@EnableTransactionManagement,@EnableAspectJAutoProxy兩個注解的淵源,然后得出結論:如果同時存在,最終只能存在一個優先級更高的BeanPostProcessor(bpp)
那么@EnableAspectJAutoProxy這個注解注入了一個優先級更高的bpp,有什么擴展點呢?我們以上圖中getAdvicesAndAdvisorsForBean方法為切入口進行分析
@EnableTransactionManagement注入的bpp沒有重寫findCandidateAdvisors方法,其查找Advisor的方法為父類的默認實現。@EnableAspectJAutoProxy注解注入的bpp重寫了findCandidateAdvisors方法,其在父類方法的基礎上又試圖通過BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法尋找更多的Advisor,最后再判斷這些找到的Advisors是否可以作用在當前bean,如果存在可以作用于當前bean的Advisors,則進行AOP動態代理
?總結
ProxyFactory這個類在Spring完成AOP動態代理的過程中起到了重要的作用,具體如下所述
- 可以通過配置決定Spring進行aop動態代理的方式,比如將@EnableTransactionManagement注解的proxyTargetClass參數設置為true(不能保證一定進行cglib動態代理,具體可以查看DefaultAopProxyFactory的createAopProxy方法)
- 可以設置監聽器,監聽動態代理對象
- 可以決定是否提前暴露代理對象,比如將@EnableAspectJAutoProxy注解的exposeProxy參數設置為true,然后通過AopContext.currentProxy()就可以獲取原始對象
- 可以通過查找是否存在作用于指定bean的Advisors,來決定是否需要進行動態代理