spring支持的AOP的方式有:AspecJ,ProxyFactoryBean,ProxyFactory
其中:AspectJ是目前大家最常用的 起到集成AspectJ和Spring,ProxyFactoryBean是將我們的AOP和IOC融合起來(lái),而ProxyFactory 則是只能通過代碼硬編碼進(jìn)行編寫 一般都是給spring自己使用
AnnotationAwareAspectJAutoProxyCreator 通過繼承SmartInstantiationAwareBeanPostProcessor 來(lái)將AsepctJ融入spring 內(nèi)部生成的代理對(duì)象是采用ProxyFactory
涉及到的幾個(gè)關(guān)鍵類
ProxyConfig:為上面三個(gè)類提供配置屬性
AdvisedSupport:繼承ProxyConfig,實(shí)現(xiàn)了Advised。封裝了對(duì)通知(Advise)和通知器(Advisor)的操作
ProxyCreatorSupport:繼承AdvisedSupport,其幫助子類(上面三個(gè)類)創(chuàng)建JDK或者cglib的代理對(duì)象
Advised:可以獲取攔截器和其他 advice, Advisors和代理接口
涉及到的幾個(gè)關(guān)鍵概念
Advice:通知,定義在連接點(diǎn)做什么,比如我們?cè)诜椒ㄇ昂筮M(jìn)行日志打印
pointcut:切點(diǎn),決定advice應(yīng)該作用于那個(gè)連接點(diǎn),比如根據(jù)正則等規(guī)則匹配哪些方法需要增強(qiáng)
Pointcut 目前有g(shù)etClassFilter(類匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配)
JoinPoint:連接點(diǎn),就是spring允許你是通知(Advice)的地方,那可就真多了,基本每個(gè)方法的錢、后(兩者都有也行),或拋出異常是時(shí)都可以是連接點(diǎn),spring只支持方法連接點(diǎn)。其他如AspectJ還可以讓你在構(gòu)造器或?qū)傩宰⑷霑r(shí)都行,不過那不是咱們關(guān)注的,只要記住,和方法有關(guān)的前前后后都是連接點(diǎn)。
advisor:把pointcut和advice連接起來(lái)
ProxyFactory
public static void main(String[] args) {
MarshallService marshallService = new MarshallService();
ProxyFactory proxyFactory = new ProxyFactory(marshallService);
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("MethodBeforeAdvice1 method=" + method.getName());
}
});
proxyFactory.addAdvice(new MarshallAdvice());
MarshallService proxy = (MarshallService) proxyFactory.getProxy();
proxy.say1();
proxy.say2();
}
1.ProxyFactory proxyFactory = new ProxyFactory(marshallService); 分別設(shè)置AdvisedSupport類的targetSource,interfaces,并且清空methodCache
targetSource:我們需要代理的原始對(duì)象,interfaces:該原始對(duì)象實(shí)現(xiàn)的接口,methodCache:保存某個(gè)方法對(duì)應(yīng)的advisor chain List
3.proxyFactory.addAdvice(new MarshallAdvice()); 添加advice,先判斷advice的類型,然后將其包裝成不同的advisor,一般都是默認(rèn)的DefaultPointcutAdvisor,然添加進(jìn)入集合advisors,并且更新相應(yīng)的數(shù)組advisorArray(為了方便操作)
4 . MarshallService proxy = (MarshallService) proxyFactory.getProxy(); 獲取代理對(duì)象
5 . 首先調(diào)用了父類ProxyCreatorSupport的createAopProxy去激活(即激活相關(guān)的監(jiān)聽事件),然后獲取AopProxyFactory,通過這factory獲取AopProxy(ObjenesisCglibAopProxy,JdkDynamicAopProxy),通過AopProxy獲取真正的代理對(duì)象
cglib
6.AopProxy.getProxy()方法對(duì)于cglib主要是設(shè)置enhancer的Callback,這些callback會(huì)在代理對(duì)象執(zhí)行方法時(shí)候調(diào)用,callback的類型有
MethodInterceptor:這就是我們aop,因?yàn)?MethodInterceptor的效率不高,它需要產(chǎn)生不同類型的字節(jié)碼,并且需要生成一些運(yùn)行時(shí)對(duì)象(InvocationHandler就不需要),所以Cglib提供了其它的接口供我們選擇
NoOp:簡(jiǎn)單地把方法調(diào)用委托給了被代理類的原方法(本例中是Person),不做任何其它的操作
LazyLoader:,它也提供了一個(gè)方法:Object loadObject() throws Exception;,loadObject()方法會(huì)在第一次被代理類的方法調(diào)用時(shí)觸發(fā),它返回一個(gè)代理類的對(duì)象,這個(gè)對(duì)象會(huì)被存儲(chǔ)起來(lái)然后負(fù)責(zé)所有被代理類方法的調(diào)用
Dispatcher :也是提供了loadObject()方法,這個(gè)方法同樣地返回一個(gè)代理對(duì)象,這個(gè)對(duì)象同樣可以代理原方法的調(diào)用。不過它們之間不同的地方在于,Dispatcher的loadObject()方法在每次發(fā)生對(duì)原方法的調(diào)用時(shí)都會(huì)被調(diào)用并返回一個(gè)代理對(duì)象來(lái)調(diào)用原方法。也就是說Dispatcher的loadObject()方法返回的對(duì)象并不會(huì)被存儲(chǔ)起來(lái),可以類比成Spring中的Prototype類型,而LazyLoader則是lazy模式的Singleton
InvocationHandler:它的使用方式和MethodInterceptor差不多,所有對(duì)invoke()方法的參數(shù)proxy對(duì)象的方法調(diào)用都會(huì)被委托給同一個(gè)InvocationHandler,所以可能會(huì)導(dǎo)致無(wú)限循環(huán)
FixedValue:同樣也提供了一個(gè)loadObject()方法,不過這個(gè)方法返回的不是代理對(duì)象,而是原方法調(diào)用想要的結(jié)果。也就是說,在這個(gè)Callback里面,看不到任何原方法的信息,也就沒有調(diào)用原方法的邏輯,不管原方法是什么都只會(huì)調(diào)用loadObject()并返回一個(gè)結(jié)果。聽起來(lái)可能有些沒有,但是配合CllbackFilter可以強(qiáng)制使某個(gè)方法返回固定的值,并且?guī)?lái)的開銷很小。需要注意的是,如果loadObject()方法的返回值并不能轉(zhuǎn)換成原方法的返回值類型,那么會(huì)拋出類型轉(zhuǎn)換異常。
jdk
- 除了生成字節(jié)碼不一樣其他的都類似 都是調(diào)用方法時(shí)候被攔截然后通過ProxyCreatorSupport類getInterceptorsAndDynamicInterceptionAdvice獲取每個(gè)方法對(duì)應(yīng)的advice
8.spring 的AspectJ代理好像就是使用ProxyFactory去生成代理
ProxyFactoryBean
具體代碼如下
MarshallProxyFactoryBean marshallProxyFactoryBean = (MarshallProxyFactoryBean)applicationContext.getBean("&MarshallProxyFactoryBean");
下面三個(gè)屬性 也可以通過xml配置
//advic
marshallProxyFactoryBean.setInterceptorNames(new String[]{"MarshallAdvice"});
//代理類實(shí)現(xiàn)的接口,如果沒有就是cglib
marshallProxyFactoryBean.setProxyInterfaces(new Class[]{MarshallInterface.class});
//需要生成proxy的對(duì)象
marshallProxyFactoryBean.setTarget(new MarshallService());
具體生成proxy
marshallProxyFactoryBean.getObject();
- getObject 就是通過initializeAdvisorChain初始化advisor
2.通過advisorAdapterRegistry 包裝咱們的advice,邏輯是如果本身就是advisor 直接返回,如果是MethodInterceptor,包裝成DefaultPointcutAdvisor(攔截所有方法),看是否是屬于AdvisorAdapter(MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter,ThrowsAdviceAdapter),也包裝成,包裝成DefaultPointcutAdvisor
3.最終都是調(diào)用CglibAopProxy或者JdkDynamicAopProxy 獲取動(dòng)態(tài)代理對(duì)象
AspectJProxyFactory
就是通過@AspectJ 獲取對(duì)應(yīng)的class 然后從class里面獲取Pointcut 即獲取匹配哪些類的哪些方法的規(guī)則,然后在獲取各個(gè)advice 組裝起來(lái)
最終通過getProxy獲取代理對(duì)象 通過父類統(tǒng)一初始化advisor和method的映射關(guān)系
總結(jié) AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大體邏輯都是填充AdvisedSupport(ProxyCreatorSupport是其子類)的,然后交給父類ProxyCreatorSupport,然后得到JDK或者CGLIB的AopProxy,代理調(diào)用時(shí)候被invoke或者intercept方法攔截 (分別在JdkDynamicAopProxy和ObjenesisCglibAopProxy的中)并且在這兩個(gè)方法中調(diào)用ProxyCreatorSupport的getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各個(gè)方法直接映射關(guān)系并緩存