AOP 術(shù)語
- 1.target:目標(biāo)類:需要被代理的類. 例如:UserService
- 2.Joinpoin:(連接點(diǎn)):所謂連接點(diǎn)是指那些可能被攔截到的點(diǎn)(方法).例如:所有的方法
- 3.PointCut 切入點(diǎn): 已經(jīng)被增強(qiáng)的連接點(diǎn).例如:addUser()
- 4.advice 通知/增強(qiáng),增強(qiáng)代碼.例如:joinpoint
- 5.Weaving(織入):是指把增強(qiáng)advice應(yīng)用到目標(biāo)對象 target 來創(chuàng)建新的代理對象proxy 的過程
- 6.proxy 代理類(一個類被AOP織入增強(qiáng)后,就產(chǎn)生一個結(jié)果代理類)
- 7.Aspect(切面):是切入點(diǎn)pointCut和通知advice (引介)的結(jié)合
一個切入點(diǎn)和一個通知(增強(qiáng)) 就組成一個特殊的面
2.2.1 JDK動態(tài)代理
- JDK動態(tài)代理對"裝飾者"設(shè)計模式簡化 .使用前提:必須有接口
1.目標(biāo)類:接口+實現(xiàn)類
2.切面類:用于存通知 MyAspect
3.工廠類:編寫工廠去生成代理
4.測試
2.2.2 CGLIB 字節(jié)碼增強(qiáng)
- 沒有接口,只有實現(xiàn)類.
- 采用字節(jié)碼增強(qiáng)框架 cglib,在運(yùn)行時創(chuàng)建目標(biāo)類的子類,從而對目標(biāo)類增強(qiáng).
- 導(dǎo)入jar包:
手動方式:
自動方式:
2.4 Spring 編寫代理:半自動
- 讓spring 創(chuàng)建代理對象,從spring容器中手動的獲取代理對象
<!--創(chuàng)建目標(biāo)類-->
<bean id="userService" class="com.xft.b_factory_bean.UserServiceImpl"></bean>
<!--創(chuàng)建處理類-->
<bean id="myAspect" class="com.xft.b_factory_bean.MyAspect"></bean>
<!--創(chuàng)建代理類
使用工廠bean FactoryBean,底層調(diào)用getObject() 返回特殊bean
ProxyFactoryBean 用于創(chuàng)建代理工廠bean,生成特殊代理對象
interfaces : 需要的接口們
通過<array>可以設(shè)置多個值
只有一個值時,value=""
target : 確定目標(biāo)類
interceptorNames: 通知 切面類的名稱,類型是String[],如果設(shè)置一個值value=""
optimize:強(qiáng)制使用CGLIB
如果目標(biāo)類有接口,采用jdk動態(tài)代理
如果沒有接口,采用cglib字節(jié)碼增強(qiáng)
如果聲明 optimize = true ,無論是否有接口,都采用cglib
-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.xft.b_factory_bean.UserService"></property>
<property name="target" ref="userService"></property>
<property name="interceptorNames" value="myAspect"></property>
<property name="optimize" value="true"></property>
</bean>
2.5 spring aop編程:全自動 [掌握]
- 從spring容器獲得目標(biāo)類,如果配置aop,spring將自動生成代理
- 要確定目標(biāo)類,aspectj 切入點(diǎn)表達(dá)式
<!--創(chuàng)建目標(biāo)類-->
<bean id="userService" class="com.xft.c_spring_aop.UserServiceImpl"></bean>
<!--創(chuàng)建切面類(通知)-->
<bean id="myAspect" class="com.xft.c_spring_aop.MyAspect"></bean>
<!--3.aop編程
3.1 導(dǎo)入命名空間
3.2 使用 <aop:config> 進(jìn)行配置
proxy-target-class="true" 聲明時使用cglib代理
<aop:pointcut> 切入點(diǎn),從目標(biāo)對象獲得具體方法
<aop:advisor> 特殊的切面,只有一個通知和一個切入點(diǎn)
advice-ref 通知引用
pointcut-ref 切入點(diǎn)引用
3.3 切入點(diǎn)表達(dá)式
execution(* com.xft.c_spring_aop.UserServiceImpl.*.*(..))
選擇方法 返回值任意 包 類名任意 方法名任意 參數(shù)任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="myPointCut" expression="execution(* com.xft.c_spring_aop.*.*(..))" />
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut" />
</aop:config>
3 AspectJ
3.1 介紹
- AspectJ 是一個基于Java語言的AOP框架
- Spring2.0以后新增了對AspectJ切點(diǎn)表達(dá)式支持
@AspectJ 是AspectJ1.5新增功能通過JDK5 注解技術(shù),允許直接在Bean類中定義切面.新版本Spring框架,建議使用AspectJ方式來開發(fā)AOP - 主要用途:自定義開發(fā)
3.2 切入點(diǎn)表達(dá)式 {掌握}
1. execution() 用于描述方法
語法:execution(修飾符 返回值 包.類.方法(參數(shù))throws 異常)
修飾符,一般省略
public 公共方法
* 任意
返回值,
void 返回沒有值
String 返回值字符串
* 任意
包,[省略]
com.xft.xxx 固定包名
com.xft.xxx*.service xxx包下面子包任意 (例如:com.xft.xxx.ssss.service)
com.xft.xxx.. xxx包下面所有子包
com.xft.xxx.*.service.. xxx包下面任意包,固定目錄service,service目錄任意包
類,[省略]
UserServiceImpl 指定類
*Impl 以Impl結(jié)尾
User* 以User開頭
* 任意
方法名,不能省略
addUser 固定方法
add* 以add開頭
*Do 以Do結(jié)尾
* 任意
(參數(shù))
() 無參
(int) 一個整型
(int,int) 兩個整型
(..) 任意參數(shù)
throw,可以省略,一般不寫
綜合1
execution(* com.xft.xxx.*.service..*.*(..))
綜合2
<aop:pointcut express="execution(* com.xft.*.withCommit*(..))||
execution(* com.xft.*Service.*(..))" id="myPointCut">
2.within:匹配包或者子包中的方法
within(cn.itcaset.aop..*)
3.this:匹配實現(xiàn)接口的代理對象中的方法
this(cn.itcast.aop.user.UserDAO)
4.target:匹配實現(xiàn)接口的目標(biāo)對象中的方法
target(cn.itcase.aop.user.UserDAO)
5.args:匹配參數(shù)格式符號標(biāo)準(zhǔn)的方法
args(int,int )
6.bean(id) 對指定的bean所有的方法
bean('userServiceId')
3.3 AspectJ 通知類型
- aop聯(lián)盟定義的通知類型,具有特性接口,必須實現(xiàn),從而確定方法名稱
- aspectj 通知類型,只定義類型名稱,已經(jīng)方法格式
- 個數(shù):6種
- before前置通知(應(yīng)用:各種校驗) 在方法執(zhí)行前執(zhí)行,如果通知拋出異常,阻止方法運(yùn)行
- afterReturning:后置通知(應(yīng)用:常規(guī)數(shù)據(jù)處理) 方法正常返回后執(zhí)行,如果方法中拋出異常,通知無法執(zhí), 必須在方法執(zhí)行后才執(zhí)行,所以可以獲得方法的返回值
- around:環(huán)繞通知(應(yīng)用:十分強(qiáng)大,可以做任何事) 方法執(zhí)行前后分別執(zhí)行,可以阻止方法的執(zhí)行
- afterThrowing:拋出異常通知(應(yīng)用:包裝異常信息) 方法拋出異常后執(zhí)行,如果方法沒有拋出異常,無法執(zhí)行
- after:最終通知(應(yīng)用:清理現(xiàn)場) 方法執(zhí)行完畢后執(zhí)行,無論方法中是否出現(xiàn)異常
3.4 基于xml
- 目標(biāo)類:接口+實現(xiàn)
- 切面類:編寫多個通知,采用aspectj通知名稱任意(方法名任意)
- aop編程,將通知應(yīng)用到目標(biāo)類
- 測試
3.4 基于注解
3.4.1替換bean
<!--創(chuàng)建目標(biāo)類-->
<bean id="userService" class="com.xft.d_aspect.b_anno.UserServiceImpl"></bean>
<!--創(chuàng)建切面類(通知)-->
<bean id="myAspect" class="com.xft.d_aspect.b_anno.MyAspect"></bean>
aop注解總結(jié)
@Aspect 聲明切面,修飾切面類,從而獲得,通知
通知
@Before 前置
@AfterReturning 后置
@Around 環(huán)繞
@AfterThrowing 拋出異常
@After 最終
切入點(diǎn)
@PointCut,修飾方法 private void xxx(){} 之后通過"方法名"獲得切入點(diǎn)