#### AOP(面向切面編程)作用及其優(yōu)勢
作用:在程序運行期間,在不修改源碼的情況下對方法進行功能增強(通知)
優(yōu)勢:減少重復(fù)代碼,提高代碼復(fù)用性,提高代碼可維護性,提高代碼可擴展性
#### AOP的底層實現(xiàn)原理
動態(tài)代理:JDK動態(tài)代理 【基于接口的動態(tài)代理技術(shù)】(基于反射)、CGLIB動態(tài)代理【基于父類的動態(tài)代理技術(shù)】
實際上,AOP的底層是通過Spring提供的動態(tài)代理技術(shù)實現(xiàn)的。在運行期間,Spring通過動態(tài)代理技術(shù)動態(tài)生成代理對象,代理對象方法執(zhí)行時進行增強功能(通知)的介入,再去調(diào)用目標對象的方法(系統(tǒng)功能),從而完成功能的增強。
+ JDK動態(tài)代理:要實現(xiàn)InvocationHandler接口(java.lang.reflect.InvocationHandler),重寫invoke方法,通過Proxy.newProxyInstance()方法創(chuàng)建代理對象。(反射)
+ Cglib動態(tài)代理:要實現(xiàn)MethodInterceptor接口(org.springframework.cglib.proxy.MethodInterceptor),重寫intercept方法,通過Enhancer.create()方法創(chuàng)建代理對象
// 可以在啟動時,設(shè)置保存生成的代理類文件
System.getProperties().put( "sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" );
#### AOP的相關(guān)概念
+ Target:目標對象,被代理的對象
+ Proxy:代理對象,代理目標對象
+ Joinpoint:連接點,目標對象中可以被增強的方法
+ Pointcut:切入點,被增強的方法集合(對哪些Joinpoint進行攔截的定義)
+ Advice:通知,增強的代碼(攔截到Joinpoint后要執(zhí)行的代碼)
+ Aspect:切面,切入點+通知
+ Weaving:織入,將通知應(yīng)用到目標對象并創(chuàng)建代理對象的過程
#### AOP源碼解析
1.須知:
-.在使用ApplicationContentext相關(guān)實現(xiàn)類加載ben的時候,會針對所有單例且非懶加載的bean,在構(gòu)造ApplicationContext的時候就會創(chuàng)建好這些bean,而不會
等到使用的時候才會創(chuàng)建。這也就是單例bean默認非懶加載的應(yīng)用。
-.讀者需要了解BeanPostProcessor接口,這個接口是Spring提供的一個擴展接口,用于在bean初始化前后做一些處理工作。
- 結(jié)合以上兩點,被代理后的bean,實際在ApplicationContext構(gòu)造完成之后就已經(jīng)被創(chuàng)建完成,getBean()的操作直接從singletonObjects中獲取即可。
2. 注冊自動代理創(chuàng)建器
- 但凡注解都有對應(yīng)的解析器,以用來解析該注解的行為。而且所有的解析器父類為:NamespaceHandlerSupport,這個類是用來解析xml配置文件的。(可以通過調(diào)用鏈查看)
- 解析xml配置文件的時候,會調(diào)用NamespaceHandlerSupport的init()方法,這個方法會調(diào)用registerBeanDefinitionParser()方法,這個方法會將解析器注冊到一個map中。
- Spring中將標簽分為兩大類:default(默認)和custom(拓展)
default namespace 涉及到的只有四個標簽:import、alias、bean、beans 【使用方法parseDefaultElement(ele,delegate)】
custom namespace 涉及到的標簽:mvc、task、context、aop等
- 以aop為例,解析器為AopNamespaceHandler,解析器會調(diào)用registerBeanDefinitionParser()方法,將解析器(AspectJAutoProxyBeanDefinitionParser)注冊到一個map中。AspectJAutoProxyBeanDefinitionParser實現(xiàn)了BeanDefinitionParser接口,重寫了parse()方法,這個方法會調(diào)用registerAutoProxyCreatorIfNecessary()方法【將AnnotationAwareAspectJAutoProxyCreator注冊到Spring容器中,把bean交給spring去托管】
- 查看AnnotationAwareAspectJAutoProxyCreator的類層次結(jié)構(gòu),可知其父類為AbstractAutoProxyCreator,這個類實現(xiàn)了BeanPostProcessor接口,重寫了postProcessAfterInitialization()方法(模板方法)
- 通過調(diào)用鏈查看,AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法會調(diào)用wrapIfNecessary()方法,這個方法會調(diào)用createProxy()方法(將所有有Advice的bean重新包裝成proxy)
3. 執(zhí)行邏輯:代理對象創(chuàng)建好后,其攔截方法的操作都是交給Methodinvocation去做,JdkDynamicAopProxy交給ReflectiveMethodInvocation,ObjenesisCglibAopProxy交給CglibMethodInvocation.
類的繼承關(guān)系(父->子)前面三個都是aopalliance下的
Joinpoint->Invocation->MethodInvocation(org.aopalliance.intercepet.MethodInvocation)->ProxyMethodInvocation->ReflectiveMethodInvocation->CglibMethodInvocation
這里說明一下JdkDunamicAopProxy的proceed()[繼承自JoinPoint,執(zhí)行鏈執(zhí)行]方法
//這里是JdkDynamicAopProxy的執(zhí)行的核心,要執(zhí)行方法,執(zhí)行通知都在這里搞定[遞歸調(diào)用,執(zhí)行所有過濾器鏈的邏輯]
```
@Override
@Nullable
public Object proceed() throws Throwable {//this.currentInterceptorIndex初始值為-1,如果執(zhí)行到執(zhí)行鏈的末尾,則直接調(diào)用連接點方法(即目標方法)if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMathers,size() -1){//該方法內(nèi)部邏輯調(diào)用目標方法return invokeJoinponit();}//獲取集合中的MethodInterceptor,執(zhí)行鏈索引加1(這里的+1保證是遞歸調(diào)用而不是循環(huán)調(diào)用)Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMathers.get(++this.currentInterceptorIndex);//InterceptorAndDynamicMethodMacher有兩個屬性MethodInterceptor,MethodMatcher,看看在advisor chain是否能夠匹配上if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMacher){InterceptorAndDynamicMethodMacher dm = (InterceptorAndDynamicMethodMacher) interceptorOrInterceptionAdvice;//判斷攔截器是否適用這個目標方法,是 執(zhí)行這個攔截器 否 跳過這個攔截器進入下一個攔截器if(dm.methodMatcher.matches(this.method,this.targetClass,this.arguments)){//攔截器的內(nèi)部,除自己邏輯外,也會有mi.proceed()保證執(zhí)行到下一個攔截器return dm.interceptor.invoke(this);}else{return proceed();}}else {//MethodInterceptor直接執(zhí)行(只有匹配上的方法才會在攔截器鏈中)return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);}
}
```