spring支持的AOP的方式有:AspecJ,ProxyFactoryBean,ProxyFactory
其中:AspectJ是目前大家最常用的 起到集成AspectJ和Spring玄货,ProxyFactoryBean是將我們的AOP和IOC融合起來,而ProxyFactory 則是只能通過代碼硬編碼進(jìn)行編寫 一般都是給spring自己使用
AnnotationAwareAspectJAutoProxyCreator 通過繼承SmartInstantiationAwareBeanPostProcessor 來將AsepctJ融入spring 內(nèi)部生成的代理對象是采用ProxyFactory
涉及到的幾個關(guān)鍵類
ProxyConfig:為上面三個類提供配置屬性
AdvisedSupport:繼承ProxyConfig,實現(xiàn)了Advised羔砾。封裝了對通知(Advise)和通知器(Advisor)的操作
ProxyCreatorSupport:繼承AdvisedSupport砾医,其幫助子類(上面三個類)創(chuàng)建JDK或者cglib的代理對象
Advised:可以獲取攔截器和其他 advice, Advisors和代理接口
涉及到的幾個關(guān)鍵概念
Advice:通知带污,定義在連接點做什么,比如我們在方法前后進(jìn)行日志打印
pointcut:切點宛琅,決定advice應(yīng)該作用于那個連接點脾歇,比如根據(jù)正則等規(guī)則匹配哪些方法需要增強
Pointcut 目前有g(shù)etClassFilter(類匹配)臀晃,getMethodMatcher(方法匹配),Pointcut TRUE (全匹配)
JoinPoint:連接點介劫,就是spring允許你是通知(Advice)的地方徽惋,那可就真多了,基本每個方法的錢座韵、后(兩者都有也行)险绘,或拋出異常是時都可以是連接點,spring只支持方法連接點誉碴。其他如AspectJ還可以讓你在構(gòu)造器或?qū)傩宰⑷霑r都行宦棺,不過那不是咱們關(guān)注的,只要記住黔帕,和方法有關(guān)的前前后后都是連接點代咸。
advisor:把pointcut和advice連接起來
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:我們需要代理的原始對象呐芥,interfaces:該原始對象實現(xiàn)的接口,methodCache:保存某個方法對應(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(); 獲取代理對象
5 . 首先調(diào)用了父類ProxyCreatorSupport的createAopProxy去激活(即激活相關(guān)的監(jiān)聽事件),然后獲取AopProxyFactory,通過這factory獲取AopProxy(ObjenesisCglibAopProxy光绕,JdkDynamicAopProxy)女嘲,通過AopProxy獲取真正的代理對象
cglib
6.AopProxy.getProxy()方法對于cglib主要是設(shè)置enhancer的Callback,這些callback會在代理對象執(zhí)行方法時候調(diào)用诞帐,callback的類型有
MethodInterceptor:這就是我們aop欣尼,因為 MethodInterceptor的效率不高,它需要產(chǎn)生不同類型的字節(jié)碼景埃,并且需要生成一些運行時對象(InvocationHandler就不需要),所以Cglib提供了其它的接口供我們選擇
NoOp:簡單地把方法調(diào)用委托給了被代理類的原方法(本例中是Person)顶别,不做任何其它的操作
LazyLoader:谷徙,它也提供了一個方法:Object loadObject() throws Exception;,loadObject()方法會在第一次被代理類的方法調(diào)用時觸發(fā)驯绎,它返回一個代理類的對象完慧,這個對象會被存儲起來然后負(fù)責(zé)所有被代理類方法的調(diào)用
Dispatcher :也是提供了loadObject()方法,這個方法同樣地返回一個代理對象剩失,這個對象同樣可以代理原方法的調(diào)用屈尼。不過它們之間不同的地方在于,Dispatcher的loadObject()方法在每次發(fā)生對原方法的調(diào)用時都會被調(diào)用并返回一個代理對象來調(diào)用原方法拴孤。也就是說Dispatcher的loadObject()方法返回的對象并不會被存儲起來脾歧,可以類比成Spring中的Prototype類型,而LazyLoader則是lazy模式的Singleton
InvocationHandler:它的使用方式和MethodInterceptor差不多演熟,所有對invoke()方法的參數(shù)proxy對象的方法調(diào)用都會被委托給同一個InvocationHandler鞭执,所以可能會導(dǎo)致無限循環(huán)
FixedValue:同樣也提供了一個loadObject()方法,不過這個方法返回的不是代理對象芒粹,而是原方法調(diào)用想要的結(jié)果兄纺。也就是說,在這個Callback里面化漆,看不到任何原方法的信息估脆,也就沒有調(diào)用原方法的邏輯,不管原方法是什么都只會調(diào)用loadObject()并返回一個結(jié)果座云。聽起來可能有些沒有疙赠,但是配合CllbackFilter可以強制使某個方法返回固定的值,并且?guī)淼拈_銷很小朦拖。需要注意的是棺聊,如果loadObject()方法的返回值并不能轉(zhuǎn)換成原方法的返回值類型,那么會拋出類型轉(zhuǎn)換異常贞谓。
jdk
- 除了生成字節(jié)碼不一樣其他的都類似 都是調(diào)用方法時候被攔截然后通過ProxyCreatorSupport類getInterceptorsAndDynamicInterceptionAdvice獲取每個方法對應(yīng)的advice
8.spring 的AspectJ代理好像就是使用ProxyFactory去生成代理
ProxyFactoryBean
具體代碼如下
MarshallProxyFactoryBean marshallProxyFactoryBean = (MarshallProxyFactoryBean)applicationContext.getBean("&MarshallProxyFactoryBean");
下面三個屬性 也可以通過xml配置
//advic
marshallProxyFactoryBean.setInterceptorNames(new String[]{"MarshallAdvice"});
//代理類實現(xiàn)的接口限佩,如果沒有就是cglib
marshallProxyFactoryBean.setProxyInterfaces(new Class[]{MarshallInterface.class});
//需要生成proxy的對象
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 獲取動態(tài)代理對象
AspectJProxyFactory
就是通過@AspectJ 獲取對應(yīng)的class 然后從class里面獲取Pointcut 即獲取匹配哪些類的哪些方法的規(guī)則砖顷,然后在獲取各個advice 組裝起來
最終通過getProxy獲取代理對象 通過父類統(tǒng)一初始化advisor和method的映射關(guān)系
總結(jié) AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大體邏輯都是填充AdvisedSupport(ProxyCreatorSupport是其子類)的贰锁,然后交給父類ProxyCreatorSupport,然后得到JDK或者CGLIB的AopProxy滤蝠,代理調(diào)用時候被invoke或者intercept方法攔截 (分別在JdkDynamicAopProxy和ObjenesisCglibAopProxy的中)并且在這兩個方法中調(diào)用ProxyCreatorSupport的getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各個方法直接映射關(guān)系并緩存