現在AOP的場景越來越多,所以我們有必要理解下和AOP相關的一些概念和機制。基礎知識和原理類大家搜索spring aop/aspectj,有大量現成的可以參考,基本上只要理解了jdk動態代理、cglib字節碼動態生成代理就足夠了,而且必須知道這個代理類是spring托管的(如果是自己創建的代理類,是無法被攔截的,此時只能使用過濾器/攔截器機制,他們本身是鏈式的,跟代理無關),所以這里就不重復廢話了。
import org.aspectj.lang.reflect.SourceLocation; public interface JoinPoint { String toString(); //連接點所在位置的相關信息 String toShortString(); //連接點所在位置的簡短相關信息 String toLongString(); //連接點所在位置的全部相關信息 Object getThis(); //返回AOP代理對象,也就是com.sun.proxy.$Proxy18 Object getTarget(); //返回目標對象,一般我們都需要它或者(也就是定義方法的接口或類,為什么會是接口呢?這主要是在目標對象本身是動態代理的情況下,例如Mapper。所以返回的是定義方法的對象如aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>) Object[] getArgs(); //返回被通知方法參數列表 Signature getSignature(); //返回當前連接點簽名 其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete()或com.b.base.BaseMapper.insert(T)(需要注意的是,很多時候我們定義了子類繼承父類的時候,我們希望拿到基於子類的FQN,這直接可拿不到,要依賴於AopUtils.getTargetClass(point.getTarget())獲取原始代理對象,下面會詳細講解) SourceLocation getSourceLocation();//返回連接點方法所在類文件中的位置 String getKind(); //連接點類型 StaticPart getStaticPart(); //返回連接點靜態部分 } public interface ProceedingJoinPoint extends JoinPoint { public Object proceed() throws Throwable; public Object proceed(Object[] args) throws Throwable; }
public interface StaticPart { Signature getSignature(); //返回當前連接點簽名 String getKind(); //連接點類型 int getId(); //唯一標識 String toString(); //連接點所在位置的相關信息 String toShortString(); //連接點所在位置的簡短相關信息 String toLongString(); //連接點所在位置的全部相關信息 }
環繞通知 ProceedingJoinPoint 執行proceed方法的作用是讓目標方法執行,這也是環繞通知和前置、后置通知方法的一個最大區別。
Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。proceed很重要,這個是aop代理鏈執行的方法。

public Object around(ProceedingJoinPoint point) throws Throwable { Signature signature = point.getSignature();
// AopUtils.getTargetClass(point.getTarget())獲取原始對象,例如對於Mapper而言,它獲取的是具體代理的Mapper如com.b.mapper.DefaultDsMapper(如果前者繼承了后者的話)而不是定義該方法的Mapper如com.b.base.BaseMapper<Info, InfoExample, InfoKey>,如下圖 Type[] types = AopUtils.getTargetClass(point.getTarget()).getGenericInterfaces(); // getGenericInterfaces方法能夠獲取類/接口實現的所有接口 Annotation nologgingAnno = ((Class)types[0]).getAnnotation(Nologging.class); // type是所有類型的父接口 MethodSignature methodSignature = (MethodSignature)signature; Method targetMethod = methodSignature.getMethod();
現在來補充下Java中Type接口與Class類的區別聯系。
package java.lang.reflect; /** * Type is the common superinterface for all types in the Java * programming language. These include raw types, parameterized types, * array types, type variables and primitive types. * * @since 1.5 */ public interface Type { /** * Returns a string describing this type, including information * about any type parameters. * * @implSpec The default implementation calls {@code toString}. * * @return a string describing this type * @since 1.8 */ default String getTypeName() { return toString(); } }
其主要的子類包括:
總結來說:
- Type是一個接口。
- Type是Java中所有類型的父接口,有一些子類,如上所示。
- Type包括:raw type(原始類型,對應Class),parameterized types(參數化類型), array types(數組類型), type variables(類型變量) and primitive types(基本類型,對應Class).
- Type是JDK1.5引入的,主要是為了泛型。
Type接口與Class類的區別聯系
- Type是Class的父接口。
- Class是Type的子類。
提示:因為AOP是基於動態代理生成,如果想要仔細研究生成的代理類長什么樣,可以設置系統參數-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true,這樣就會保存所有自動生成的代理類(注:生產環境嚴禁使用)。
參考:https://blog.csdn.net/cxh5060/article/details/45151863(攔截自定義注解,需要注意的是,標准的AOP表達式@annotation(com.xxx.yyy.annotation.CustomAnnotation)只能攔截實現類方法上的注解,無法攔截接口上的注解,如有需根據接口方法上的注解攔截的需求,需使用spring bean生命周期的BeanPostProcessor動態生成代理,而不是采用簡單的AOP實現)
在spring aop中,advisor其實就是切入點+行為,advise是切入點,見https://www.jianshu.com/p/2250b24a3f7d。
https://www.cnblogs.com/akaneblog/p/6720513.html(jdk動態代理手工編寫,一般框架使用,比如spring aop、mybatis中logger也使用了動態代理)
https://www.cnblogs.com/haiq/p/4304615.html、https://blog.csdn.net/xlgen157387/article/details/82497594(cglib vs jdk動態代理性能參考)
https://blog.csdn.net/u010061691/article/details/50857798(進一步加了解釋,實際上InvocationHandler是要被明確調用的,只不過在AOP中通常被框架調用了,如果是應用自己編寫的話,則需要代碼中通過InvocationHandler.getProxy,然后強轉、再調用。https://dzone.com/articles/java-dynamic-proxies)
https://dzone.com/articles/cglib-missing-manual(cglib手冊)
spring aop支持(https://www.cnblogs.com/V1haoge/p/9560803.html)
spring aop/aspectj修飾的bean的代理創建過程:https://segmentfault.com/a/1190000018281577