青島開發(fā)區(qū)網(wǎng)站建設(shè)多少錢百度競價排名的利與弊
目錄標(biāo)題
- AOP定義
- SpringAOP和AspectJ聯(lián)系
- Spring如何實現(xiàn)AOP
- AOP的代理對象
- AOP的代理對象生成過程
AOP定義
- AOP (Aspect Orient Programming):直譯過來就是 面向切面編程。AOP 是一種編程思想
- 用途:
- Transactions (事務(wù)調(diào)用方法前開啟事務(wù), 調(diào)用方法后提交關(guān)閉事務(wù) )、日志、性能(監(jiān)控方法運行時間)、權(quán)限控制等。也就是對業(yè)務(wù)方法做了增強
SpringAOP和AspectJ聯(lián)系
- Spring AOP旨在通過Spring IoC提供一個簡單的AOP實現(xiàn),以解決編碼人員面臨的最常出現(xiàn)的問題。這并不是完整的AOP解決方案,它只能用于Spring容器管理的beans。
- AspectJ是最原始的AOP實現(xiàn)技術(shù),提供了完整的AOP解決方案。
- 簡單的:spirng aop夠用了,但是spring aop借助了aspectj的注解功能,需要添加aspectj的依賴。
- 在高級點,比如切面很多,上萬個,這是就要用到aspectj的高級功能了
- 在Spring的框架中包含Aspectj,當(dāng)然也包括Spring AOP,在進行開發(fā)時候,這兩個框架是完全兼容的
- 區(qū)別:
- AspectJ使用的是編譯期和類加載時進行織入
- Spring AOP利用的是運行時織入
Spring如何實現(xiàn)AOP
AOP的代理對象
都知道AOP是通過代理對象實現(xiàn)對對象功能的增強,代理對象分為靜態(tài)代理和動態(tài)代理
靜態(tài)代理
- 需要定義接口、目標(biāo)對象與代理對象
- 代理類需要對代理對象的每個方法有對應(yīng)方法
- 優(yōu)點
- 也就是代理模式的優(yōu)點,可以在被代理方法的執(zhí)行前或后加入別的代碼,實現(xiàn)諸如權(quán)限及日志的操作
- 不是運行時生成的代理,效率更高
- 缺點
- 如果代理對象增加一個方法,所有代理類也需要實現(xiàn)此方法
動態(tài)代理
- 動態(tài)代理類的源碼是在程序運行期間由JVM根據(jù)反射等機制動態(tài)織入的
- 不存在代理類的字節(jié)碼文件,直接進了虛擬機
- 通過proxy提供了一組靜態(tài)方法來為一組接口動態(tài)地生成代理類及其對象。
// 方法 1: 該方法用于獲取指定代理對象所關(guān)聯(lián)的調(diào)用處理器
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:該方法用于獲取關(guān)聯(lián)于指定類裝載器和一組接口的動態(tài)代理類的類對象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:該方法用于判斷指定類對象是否是一個動態(tài)代理類
static boolean isProxyClass(Class cl)
// 方法 4:該方法用于為指定類裝載器、一組接口及調(diào)用處理器生成動態(tài)代理類實例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h)
注意newProxyInstance方法,接收的三個參數(shù)依次為:
ClassLoader loader, :指定當(dāng)前目標(biāo)對象使用類加載器 ;負(fù)責(zé)將類的字節(jié)碼裝載到 Java 虛擬機(JVM)中并為其定義類對象
Class<?>[] interfaces, :目標(biāo)對象實現(xiàn)的接口的類型,使用泛型方式確認(rèn)類型
InvocationHandler h :事件處理,執(zhí)行目標(biāo)對象的方法時,會觸發(fā)事件處理器的方法,會把當(dāng)前執(zhí)行目標(biāo)對象的方法作為參數(shù)傳入
InvocationHandler,這是調(diào)用處理器接口,它自定義了一個 invoke 方法,在該方法中實現(xiàn)對目標(biāo)類的代理訪問。
public interface InvocationHandler {
//第一個參數(shù)既是代理類實例
//第二個參數(shù)是被調(diào)用的方法對象
// 第三個方法是調(diào)用參數(shù)Object invoke(Object proxy, Method method, Object[] args)
}
所以實現(xiàn)動態(tài)代理,我們就需要創(chuàng)造一個類實現(xiàn)InvocationHandler接口,并且實現(xiàn)invoke方法
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable {
//********************方法前增強***************************
// 反射調(diào)用目標(biāo)方法return method.invoke(obj, args);
//********************方法后增強***************************
}
首先創(chuàng)建目標(biāo)對象,將對象作為參數(shù)傳給實現(xiàn)InvocationHandler接口的類的實例對象,然后
使用Proxy.newProxyInstance()方法,將參數(shù)傳入進去生成動態(tài)代理對象。
優(yōu)點:
- 相比靜態(tài)代理,動態(tài)代理減只需要實現(xiàn)一個接口即可完成,而靜態(tài)代理每次都要實現(xiàn)新加的方法以及維護被代理方法
AOP的代理對象生成過程
- 在處理循環(huán)依賴的時候,放入三級緩存的是ObjectFactory(一個lambda表達式,用來生成bean對象的半成品對象)。因為對象可能需要被代理所以,所以放入三級緩存的是一個ObjectFactory,而不是一個半成品bean。
- 所以AOP的代理是在后置處理器處生成的,也就是AbstractAutoProxyCreator實現(xiàn)了BeanPostProcessor接口。
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}
通過postProcessAfterInitialization方法,實現(xiàn)目標(biāo)對象的動態(tài)代理
//如果當(dāng)前的bean適合被代理,則需要包裝指定的bean@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {if (bean != null) {// 根據(jù)給定的bean的class和name構(gòu)建一個keyObject cacheKey = getCacheKey(bean.getClass(), beanName);if (!this.earlyProxyReferences.contains(cacheKey)) {// 如果當(dāng)前的bean適合被代理,則需要包裝指定的beanreturn wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}
向下的過程依次是
- wrapIfNecessary
- createProxy
- proxyFactory.getProxy
- ProxyCreatorSupport#createAopProxy() 判斷是使用JDK代理還是CGLIB代理
- 上面選擇的AopProxy的getProxy方法
- Proxy.newProxyInstance
- 上面選擇的AopProxy的getProxy方法
- ProxyCreatorSupport#createAopProxy() 判斷是使用JDK代理還是CGLIB代理
- proxyFactory.getProxy
- createProxy
到此代理對象生成之后被放入一級緩存中。