知識點:
- 各種連接點joinPoint的意義
- spring AOP XML實現(xiàn)方式的注意事項:
- spring AOP的源碼分析
- spring5新特性
1、各種連接點joinPoint的意義
execution
用于匹配方法執(zhí)行 join points連接點,最小粒度方法,在aop中主要使用。
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
這里問號表示當前項可以有也可以沒有,其中各項的語義如下
modifiers-pattern:方法的可見性,如public,protected;
ret-type-pattern:方法的返回值類型,如int,void等;
declaring-type-pattern:方法所在類的全路徑名,如com.spring.Aspect;
name-pattern:方法名類型,如buisinessService();
param-pattern:方法的參數(shù)類型,如java.lang.String;
throws-pattern:方法拋出的異常類型,如java.lang.Exception;
example://加入Java開發(fā)交流君樣:756584822一起吹水聊天
@Pointcut("execution(* com.chenss.dao.*.*(..))")//匹配com.chenss.dao包下的任意接口和類的任意方法
@Pointcut("execution(public * com.chenss.dao.*.*(..))")//匹配com.chenss.dao包下的任意接口和類的public方法
@Pointcut("execution(public * com.chenss.dao.*.*())")//匹配com.chenss.dao包下的任意接口和類的public 無方法參數(shù)的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String, ..))")//匹配com.chenss.dao包下的任意接口和類的第一個參數(shù)為String類型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")//匹配com.chenss.dao包下的任意接口和類的只有一個參數(shù),且參數(shù)為String類型的方法
@Pointcut("execution(* com.chenss.dao.*.*(java.lang.String))")//匹配com.chenss.dao包下的任意接口和類的只有一個參數(shù),且參數(shù)為String類型的方法
@Pointcut("execution(public * *(..))")//匹配任意的public方法
@Pointcut("execution(* te*(..))")//匹配任意的以te開頭的方法
@Pointcut("execution(* com.chenss.dao.IndexDao.*(..))")//匹配com.chenss.dao.IndexDao接口中任意的方法
@Pointcut("execution(* com.chenss.dao..*.*(..))")//匹配com.chenss.dao包及其子包中任意的方法
關于這個表達式的詳細寫法,可以腦補也可以參考官網(wǎng)很容易的,可以作為一個看spring官網(wǎng)文檔的入門,打破你害怕看官方文檔的心理,其實你會發(fā)覺官方文檔也是很容易的
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop-pointcuts-examples
由于Spring切面粒度最小是達到方法級別,而execution表達式可以用于明確指定方法返回類型,類名,方法名和參數(shù)名等與方法相關的信息,并且在Spring中,大部分需要使用AOP的業(yè)務場景也只需要達到方法級別即可,因而execution表達式的使用是最為廣泛的
within
表達式的最小粒度為類
// ------------
// within與execution相比,粒度更大,僅能實現(xiàn)到包和接口、類級別。而execution可以精確到方法的返回值,參數(shù)個數(shù)、修飾符、參數(shù)類型等
@Pointcut("within(com.chenss.dao.*)")//匹配com.chenss.dao包中的任意方法
@Pointcut("within(com.chenss.dao..*)")//匹配com.chenss.dao包及其子包中的任意方法
args
args表達式的作用是匹配指定參數(shù)類型和指定參數(shù)數(shù)量的方法,與包名和類名無關
/**
* args同execution不同的地方在于:
* args匹配的是運行時傳遞給方法的參數(shù)類型
* execution(* *(java.io.Serializable))匹配的是方法在聲明時指定的方法參數(shù)類型。
*/
@Pointcut("args(java.io.Serializable)")//匹配運行時傳遞的參數(shù)類型為指定類型的、且參數(shù)個數(shù)和順序匹配
@Pointcut("@args(com.chenss.anno.Chenss)")//接受一個參數(shù),并且傳遞的參數(shù)的運行時類型具有@Classified
this JDK代理時,指向接口和代理類proxy,cglib代理時 指向接口和子類(不使用proxy)
target 指向接口和子類
/**
* 此處需要注意的是,如果配置設置proxyTargetClass=false,或默認為false,則是用JDK代理,否則使用的是CGLIB代理
* JDK代理的實現(xiàn)方式是基于接口實現(xiàn),代理類繼承Proxy,實現(xiàn)接口。
* 而CGLIB繼承被代理的類來實現(xiàn)。
* 所以使用target會保證目標不變,關聯(lián)對象不會受到這個設置的影響。
* 但是使用this對象時,會根據(jù)該選項的設置,判斷是否能找到對象。
*/
@Pointcut("target(com.chenss.dao.IndexDaoImpl)")//目標對象,也就是被代理的對象。限制目標對象為com.chenss.dao.IndexDaoImpl類
@Pointcut("this(com.chenss.dao.IndexDaoImpl)")//當前對象,也就是代理對象,代理對象時通過代理目標對象的方式獲取新的對象,與原值并非一個//加入Java開發(fā)交流君樣:756584822一起吹水聊天
@Pointcut("@target(com.chenss.anno.Chenss)")//具有@Chenss的目標對象中的任意方法
`@Pointcut("@within(com.chenss.anno.Chenss)")//等同于@targ
2、Spring AOP XML實現(xiàn)方式的注意事項:
在aop:config中定義切面邏輯,允許重復出現(xiàn),重復多次,以最后出現(xiàn)的邏輯為準,但是次數(shù)以出現(xiàn)的次數(shù)為準
aop:aspect ID重復不影響正常運行,依然能夠有正確結果
aop:pointcut ID重復會出現(xiàn)覆蓋,以最后出現(xiàn)的為準。不同aop:aspect內(nèi)出現(xiàn)的pointcut配置,可以相互引用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定義開始進行注解掃描 -->
<context:component-scan base-package="com.chenss"></context:component-scan>
<!-- 定義AspectJ對象使用的邏輯類,類中提供切面之后執(zhí)行的邏輯方法 -->
<bean id="aspectAop" class="com.chenss.aspectj.Aspect"></bean>
<bean id="aspectAop2" class="com.chenss.aspectj.Aspect2"></bean>
<bean id="indexDao" class="com.chenss.entity.IndexDao"></bean>
<!--在Config中定義切面邏輯,允許重復出現(xiàn),重復多次,以最后出現(xiàn)的邏輯為準,但是次數(shù)以出現(xiàn)的次數(shù)為準-->
<aop:config>
<!-- aop:aspect ID重復不影響正常運行,依然能夠有正確結果 -->
<!-- aop:pointcut ID重復會出現(xiàn)覆蓋,以最后出現(xiàn)的為準。不同aop:aspect內(nèi)出現(xiàn)的pointcut配置,可以相互引用 -->
<aop:aspect id="aspect" ref="aspectAop">
<aop:pointcut id="aspectCut" expression="execution(* com.chenss.entity.*.*())"/>
<aop:before method="before" pointcut-ref="aspectCut"></aop:before>
fffffff
<aop:pointcut id="aspectNameCut" expression="execution(* com.chenss.entity.*.*(java.lang.String, ..))"/>
<aop:before method="before2" pointcut-ref="aspectNameCut"></aop:before>
</aop:aspect>
</aop:config>
</beans>//加入Java開發(fā)交流君樣:756584822一起吹水聊天
3、spring AOP的源碼分析
cglib
cglib封裝了ASM這個開源框架,對字節(jié)碼操作,完成對代理類的創(chuàng)建
主要通過集成目標對象,然后完成重寫,再操作字節(jié)碼
具體看參考ASM的語法
jdk
在Proxy這個類當中首先實例化一個對象ProxyClassFactory,然后在get方法中調用了apply方法,完成對代理類的創(chuàng)建
其中最重要的兩個方法
generateProxyClass通過反射收集字段和屬性然后生成字節(jié)
defineClass0 jvm內(nèi)部完成對上述字節(jié)的load
4、spring5新特性
使用 lambda表達式定義bean
日志 spring4的日志是用jcl,原生的JCL,底層通過循環(huán)去加載具·體的日志實現(xiàn)技術,所以有先后順序,spring5利用的是spring-jcl,其實就是spring自己改了JCL的代碼具體參考視頻當中講的兩者的區(qū)別
新特性還有其他,但是這兩個比較重要,由于時間問題,其他的特性可以去網(wǎng)上找到相應資料,但是這兩個應付面試絕對可以了,其他的特性噱頭居多,實用性可能不是很大.
