1.什么是AOP
面向切面編程,它是一種編程思想。Aop采取橫向抽取機(jī)制,取代了傳統(tǒng)
縱向繼承體系重復(fù)性代碼的編寫方式(例如,性能監(jiān)視、安全檢查、日志記錄等)
AOP是OOP的思想延續(xù)
傳統(tǒng)縱向代碼復(fù)用
需求:執(zhí)行save方法時(shí),先向日志表中插入數(shù)據(jù)
class UserDao{
public void save(){
//新增插入日志的方法
//執(zhí)行保存操作
}
}
解決方式1:
直接在save方法的執(zhí)行保存操作前,出入向日志中插入數(shù)據(jù)的代碼;
但若多個(gè)方法都需要新增插入日志的操作,則非常麻煩
解決方式2:
將通用的功能(插入日志)寫在抽象基類中,然后讓需要增加通用功能的組件
UserDao繼承,使用時(shí),調(diào)入
class abstract BaseDao{
//插入日志
public void writerLog(){
//向日志中插入數(shù)據(jù)
}
}
class UserDao extends BaseDao{
public void save(){
//新增插入日志的方法
super.writerLog();
//執(zhí)行保存操作
}
}
方式2 java不推薦使用繼承的方式進(jìn)行代碼的復(fù)用
缺點(diǎn):代碼植入,有侵入性
AOP 原理
Spring AOP主要是基于動(dòng)態(tài)代理技術(shù),當(dāng)spring采用aop配置后,
spring容器返回的目標(biāo)對(duì)象(需要增加代碼的類的實(shí)例),實(shí)質(zhì)上是spring
利用動(dòng)態(tài)代理技術(shù)生成的一個(gè)代理類型,代理類型重寫原目標(biāo)對(duì)象方法的功能
在代理類中調(diào)用切面(需要代理的一些方法和增強(qiáng)代碼)和目標(biāo)對(duì)象功能
通俗的說:基于代理思想,對(duì)原來目標(biāo)對(duì)象,創(chuàng)建代理對(duì)象,在不修改原對(duì)象代碼
的情況下,通過代理對(duì)象,調(diào)用增強(qiáng)功能的代碼,從而對(duì)原有業(yè)務(wù)方法進(jìn)行
增強(qiáng)
AOP本質(zhì):將共通處理邏輯和原有傳統(tǒng)業(yè)務(wù)處理邏輯剝離,剝離后獨(dú)立封裝成組件
,之后通過配置低耦合形式切入到傳統(tǒng)業(yè)務(wù)組件中。這樣做的好處,便于日后
修改這些共通的業(yè)務(wù)邏輯時(shí),不會(huì)影響傳統(tǒng)的業(yè)務(wù)邏輯(將共通邏輯和傳統(tǒng)邏輯
進(jìn)行解耦)
AOP相關(guān)概念
Aspect(切面) :是通知和切入點(diǎn)的結(jié)合,通知和切入共同定義了關(guān)于切面的
全部?jī)?nèi)容--它的功能、在何時(shí)和何地完成其功能
jionPoint(連接點(diǎn)):所謂連接點(diǎn)指的是那些被攔截到的點(diǎn)。
在spring中,這些點(diǎn)指的是方法,因?yàn)閟pring只支持方法類型的連接點(diǎn)
pointcut(切入點(diǎn)):所謂切入點(diǎn)是指我們要對(duì)那些joinpoint進(jìn)行攔截的定義
通知定義了切面的“什么”和“何時(shí)”,切入點(diǎn)就定義了"何地"
advice(通知):所謂通知是指攔截到j(luò)oinpoint之后要做的事情(增強(qiáng)的代碼,即
共通組件及作用在目標(biāo)組件的時(shí)機(jī)(前置,后置...)
通知分為前置通知,后置通知,異常通知,最終通知,環(huán)繞通知
target(目標(biāo)對(duì)象) :代理的目標(biāo)對(duì)象
weaving(織入):是指把切面應(yīng)用到目標(biāo)對(duì)象來創(chuàng)建新的代理對(duì)象的過程:切面
在指定的連接點(diǎn)織入的目標(biāo)對(duì)象
切入點(diǎn)的表達(dá)方式
切入點(diǎn):通俗的說就是往哪些組件切入
用于指定目標(biāo)組件及其方法,在spring中使用表達(dá)式表示
三種
===方法限定表達(dá)式===
execution(修飾符? 返回類型 方法名(參數(shù)列表) throws 異常?)
//匹配UserServiceImpl的registUser方法
execution(* org.ks.cost.service.UserServiceImpl.resistUser(..))
//匹配所有l(wèi)oad開始的方法
execution(* load(..))
//匹配所有service包下所有類的所有方法
execution( org.ks.cost.service..(..))
//匹配所有service包及其子包所有類的所有方法
execution(* org.ks.cost.service...(..))
==類型限定表達(dá)式===
within(類型)
//匹配UserServiceImpl類型的所有的方法
within(org.ks.cost.service.UserServiceImpl)
//匹配service包下所有類的所有的方法
within(org.ks.cost.service.)
//匹配所有service包及其子包所有類的所有方法
within(org.ks.cost.service..)
==Bean名稱限定表達(dá)式===
bean(id名)
//匹配id=userServiceImpl組件對(duì)象的所有方法
bean("userServiceImpl")
//匹配所有id名以service結(jié)尾的組件對(duì)象的所有的方法
bean("*service")
spring aop編程的兩種方式
方式一:spring 1.2開始支持aop編程(傳統(tǒng)springaop編程)
編程非常復(fù)雜,spring框架采用了兩種動(dòng)態(tài)代理實(shí)現(xiàn)
a\利用cglib工具包
b\利用jdkProxy api
方式二:spring2.0之后支持第三方aop框架(aspectJ)實(shí)現(xiàn)另一種aop編程---推薦
步驟:
1、XML
step1、確定不表對(duì)象,確定bean對(duì)象
step2、advice(通知)的編寫
step3、配置切面(通知,切入點(diǎn),即通知和切入點(diǎn)的關(guān)聯(lián))
五種通知小結(jié)
1.只要掌握Around通知類型,就可以實(shí)現(xiàn)其他四種通知效果
2.可以在環(huán)繞通知的方法中按如下格式編寫代碼:
try{
//前置通知的代碼
Object reuslt=proceedingJoinPoint.proceed();
//后置通知的代碼
}catch(Exception e){
//拋出通知
}finally{
//最終通知
}