Spring通過動態代理模式的實現後,我們可以定義AOP其實就是用於通過規則設置來攔截方法,加入可以統一處理的代碼。
規則:
可以指定哪些方法要做增強,哪些方法不做增強,由Spring的AOP 統一配置即可,底層如果被代理的類有接口使用JDK動態代理,沒有接口自動CGLIB第三方代理,開發者只要配置AOP即可,不需要再編寫底層動態代理的相關代碼。
AOP相關術語
Joinpoint(連接點):
所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因爲spring只支持方法類型的連接點。
—就是根據規則,可以指定攔截的方法,我們將每一個被攔截的方法稱爲連接點。
Pointcut(切入點):
--所謂的切入點,就是攔截方法設置的規則
所謂切入點是指我們要對哪些Joinpoint進行攔截的定義。
Advice(通知/增強):
--就是可以設置在方法之前攔截或者方法執行之後攔截或者方法出異常後攔截,或者方法之前和之後都攔截。我們將這些攔截場景稱爲通知
所謂通知是指攔截到Joinpoint之後所要做的事情就是通知。
通知的類型:前置通知,後置通知,異常通知,最終通知,環繞通知。
Aspect(切面):
--所謂的切面就是我們的攔截處理類。
是切入點和通知的結合。
Weaving(織入):
把切面加入到對象,並創建出代理對象的過程。(該過程由Spring來完成)
常用標籤
<aop:config>
作用:
用於聲明開始aop的配置
<aop:aspect>
作用:
用於配置切面。
屬性:
id:給切面提供一個唯一標識。
ref:引用配置好的通知類bean的id。
<aop:pointcut>
作用:
用於配置切入點表達式
屬性:
expression:用於定義切入點表達式。
id:用於給切入點表達式提供一個唯一標識。
<aop:before>
作用:
用於配置前置通知
屬性:
method:指定通知中方法的名稱。
pointct:定義切入點表達式
pointcut-ref:指定切入點表達式的引用
<aop:after-returning>
作用:
用於配置後置通知,如果出了異常就一定不會調用切面的方法
屬性:
method:指定通知中方法的名稱。
pointct:定義切入點表達式
pointcut-ref:指定切入點表達式的引用
<aop:after-throwing>
作用:
用於配置異常通知,只有出了異常纔會調用切面對應的方法
屬性:
method:指定通知中方法的名稱。
pointct:定義切入點表達式
pointcut-ref:指定切入點表達式的引用
<aop:after>
作用:
用於配置最終通知,不管出不出異常,調用的切面的方法
屬性:
method:指定通知中方法的名稱。
pointct:定義切入點表達式
pointcut-ref:指定切入點表達式的引用
<aop:around>
作用:
用於配置環繞通知
屬性:
method:指定通知中方法的名稱。
pointct:定義切入點表達式
pointcut-ref:指定切入點表達式的引用
搭建環境
UserService 接口
package com.ywq.spring.service;
import com.ywq.spring.pojo.User;
public interface UserService {
void insert(User user);
void update(User user);
}
業務層UserServiceImpl 實現類
package com.ywq.spring.service.impl;
import com.ywq.spring.pojo.User;
import com.ywq.spring.service.UserService;
public class UserServiceImpl implements UserService{
public void insert(User user) {
System.out.println("---調用DAO層保存方法---");
}
public void update(User user) {
System.out.println("---調用DAO層修改方法---");
}
}
切面類
package com.ywq.spring;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class TransactionManagerHandler {
/**
* 環繞增強的方法
*
* @param pjp ProceedingJoinPoint 連接點 ProceedingJoinPoint 連接點
*
*/
public void allInOne(ProceedingJoinPoint pjp) {
try {
begin(pjp);
// 執行方法
pjp.proceed(); //此方法在環繞方法中可以調用正在的業務方法
System.out.println("提交事務");
} catch (Throwable e) {
System.out.println("回滾事務 :" + e.getMessage());
} finally {
System.out.println("關閉session");
}
}
// JoinPoint : 連接點, 獲取被代理對象的相關信息
public void begin(JoinPoint jp) {
// 獲取被代理對象的類型
Class<?> clz = jp.getTarget().getClass();
System.out.println(clz);
// 獲取被代理對象執行方法對應的參數
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
System.out.println("開啓事務");
}
public void begin() {
System.out.println("開啓事務");
}
public void commit() {
System.out.println("提交事務");
}
/*
* public void rollback() { System.out.println("回滾事務"); }
*/
public void rollback(Throwable e) {
System.out.println("回滾事務 : " + e.getMessage());
}
public void close() {
System.out.println("關閉session");
}
}
XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 配置UserService層 -->
<bean id="userService" class="com.ywq.spring.service.impl.UserServiceImpl"/>
<!-- 配置事物管理器 -->
<bean id="txMananger" class="com.ywq.spring.TransactionManagerHandler"/>
<!-- AOP 相關配置: W (where)W(when)W(what) 原則 -->
<!-- 配置切入點: where -->
<aop:config>
<!-- 做什麼(what:增強的功能) -->
<aop:aspect ref="txMananger">
<!-- 切入點(Pointcut):在哪些類,哪些方法上切入(where); -->
<aop:pointcut expression="execution( * com.ywq.spring.service..*.*(..))" id="pt"/>
<!-- 增強(Advice):早期翻譯爲通知,在方法執行的什麼時機(when:方法前/方法後/方法前後)
前置增強 : method : 需要增強的方法 -->
<aop:before method="begin" pointcut-ref="pt"/>
<aop:after-returning method="commit" pointcut-ref="pt"/><!-- 後置增強 -->
<!-- 異常增強 : 拋出的異是常異常頂級類Throwable
throwing : 是異常增城方法,參數的名稱: 必須和參數一致 -->
<aop:after-throwing throwing="e" method="rollback" pointcut-ref="pt"/><!-- 異常增強 -->
<aop:after method="close" pointcut-ref="pt"/><!-- 最終增強 -->
<!-- 環繞增強: 將多個增加集中到一起了 -->
<!-- <aop:around method="allInOne" pointcut-ref="pt"/> -->
</aop:aspect>
<!-- 織入(Weaving):把切面加入到對象,並創建出代理對象的過程。(該過程由Spring來完成)。 -->
</aop:config>
</beans>
測試代碼
package com.ywq.spring.test;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ywq.spring.pojo.User;
import com.ywq.spring.service.impl.UserServiceImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {
@Resource
private UserServiceImpl service;
@Test
public void testSave() {
User user = new User(null, "張三", "[email protected]");
service.insert(user);
}
@Test
public void testUpdate() {
User user = new User(1, "李四", "[email protected]");
service.update(user);
}
}