文章目錄
- AspectJ
- 通知型別(通知(Advice):在方法執行前或執行后要做的動作)
- 使用AspectJ實作Spring AOP的方式有兩種:
- 1. 基于XML配置開發AspectJ
- 案例實作
- 2. 基于注解開發AspectJ【***】
- AspectJ通知注解【***】
- 連接點(JoinPoint)【***】
- 案例
AspectJ
??AspectJ是一個基于Java語言的AOP框架,從Spring 2.0以后引入了AspectJ的支持,目前的Spring框架,建議使用AspectJ實作Spring AOP,
??AOP面向切面編程,利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率
通知型別(通知(Advice):在方法執行前或執行后要做的動作)
- 環繞通知
環繞通知(org.aopalliance.intercept.MethodInterceptor)是在目標方法執行前和執行后實施增強,可以應用于日志記錄、事務處理等功能,- 前置通知
前置通知(org.springframework.aop.MethodBeforeAdvice)是在目標方法執行前實施增強,可應用于權限管理等功能,- 后置回傳通知
后置回傳通知(org.springframework.aop.AfterReturningAdvice)是在目標方法成功執行后實施增強,可應用于關閉流、洗掉臨時檔案等功能,- 后置(最終)通知
后置通知(org.springframework.aop.AfterAdvice)是在目標方法執行后實施增強,與后置回傳通知不同的是,不管是否發生例外都要執行該通知,可應用于釋放資源,- 例外通知
例外通知(org.springframework.aop.ThrowsAdvice)是在方法拋出例外后實施增強,可以應用于處理例外、記錄日志等功能,- 引入通知
引入通知(org.springframework.aop.IntroductionInterceptor)是在目標類中添加一些新的方法和屬性,可以應用于修改目標類(增強類),
使用AspectJ實作Spring AOP的方式有兩種:
- 基于XML配置開發AspectJ
- 基于注解開發AspectJ,
1. 基于XML配置開發AspectJ
??注意:基于XML配置開發AspectJ是指通過XML組態檔定義切面、切入點及通知,所有這些定義都必須在applicationContext.xml的<aop:config>元素內,
案例實作
- pom.xml加入AspectJ的依賴
<!--AspectJ 實作Spring AOP 方式: 1、aspectJ基于XML開發 切面編程AOP 事物回滾使用-->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
- 創建被代理類(目標類)
public interface UserDao {
public void save();
public void delete();
}
public class UserDaoImpl implements UserDao{
@Override
public void save() {
// int i = 100/0;//測驗例外拋出 虛擬機終止程式運行
System.out.println("save user .....");
}
@Override
public void delete() {
System.out.println("delete user .....");
}
}
- 創建切面類
/*切面類中定義的一個個方法叫通知
advice 通知 --- 是增強的方法,應用于被代理類方法的額外功能
*/
/*
AspectJ中的切入點匹配的執行點稱作連接的(JoinPoint),
在通知方法中可以宣告一個JoinPoint型別的引數,通過JoinPoint可以訪問連接點的細節
1.java.lang.Object[] getArgs():獲取連接點方法運行時的入參串列;
2.Signature getSignature() :獲取連接點的方法簽名物件;
3.java.lang.Object getTarget() :獲取連接點所在的目標物件;
4.java.lang.Object getThis() :獲取代理物件本身;
ProceedingJoinPoint繼承JoinPoint子介面,它新增了兩個用于執行連接點方法的方法:
5.java.lang.Object proceed() throws java.lang.Throwable:通過反射執行目標物件的連接點處的方法;
6.java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通過反射執行目標物件連接點處的方法,不過使用新的引數替換原來的引數,
* */
public class MyAspect {
// 前置通知 advice
public void before(JoinPoint joinPoint){
// 被代理物件
joinPoint.getTarget();
// 目標物件被增強的方法
//獲取方法簽名物件 public void save() 【除了{}方法體以外都是方法簽名】
joinPoint.getSignature().getName();
System.out.println("前置通知,用于權限控制,,"+ joinPoint.getTarget()+" ----methodName---"+joinPoint.getSignature().getName());
}
//后置通知
public void afterReturning(JoinPoint joinPoint){
System.out.println("后置通知,清除操作過的檔案"+ joinPoint.getTarget()+" ----methodName---"+joinPoint.getSignature().getName());
}
// 環繞通知 ProceedingJoinPoint是joinPoint的子類
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環繞通知,方法執行之前,開啟事務");
joinPoint.proceed(); //讓方法繼續執行
System.out.println("環繞通知,方法執行之后,關閉事務");
}
public void afterThrowing(Throwable e) throws Throwable {
System.out.println("例外通知:方法出現例外呼叫,處理例外"+e.getMessage());
}
public void after(JoinPoint joinPoint) {
System.out.println("最終通知 管理資料庫連接等清理作業");
}
}
- 創建組態檔applicationContext.xml,撰寫相關配置
<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"
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">
<!-- 被代理類 目標類 -->
<bean id="userDao" class="com.xgf.aop.aspectj.xml.UserDaoImpl"/>
<!--切面類 干什么事情-->
<bean id="myAspect" class="com.xgf.aop.aspectj.xml.MyAspect"/>
<!-- 基于XML配置開發AspectJ是指通過XML組態檔定義切面、切入點及通知,所
有這些定義都必須在<aop:config>元素內,【***】 -->
<aop:config>
<!--引入切面類 -->
<aop:aspect ref="myAspect">
<!-- 執行的方法 在什么地方 pointcut切點
execution(回傳值型別 包名.類名.方法名(引數))
(..)代表任意引數
-->
<aop:pointcut id="mycut" expression="execution(* com.xgf.aop.aspectj.xml.*.*(..))"/>
<!-- 切入時機 -->
<!--前置通知 方法執行之前-->
<aop:before method="before" pointcut-ref="mycut"/>
<!--后置回傳通知 方法執行之后執行,方法正常結束才呼叫,出現例外不會呼叫-->
<aop:after-returning method="afterReturning" pointcut-ref="mycut"/>
<!--環繞通知 -->
<aop:around method="around" pointcut-ref="mycut"/>
<!--例外通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="mycut" throwing="e"/>
<!-- 最終(后置)通知 不管方法是否出現例外都會執行,進行資源釋放等清理作業 -->
<aop:after method="after" pointcut-ref="mycut"/>
</aop:aspect>
</aop:config>
</beans>
- 撰寫測驗類
public class AspectJXMLTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("com/xgf/aop/aspectj/xml/applicationContext.xml");
/* 代理類 */
UserDao userDao = (UserDao) context.getBean("userDao");
userDao.save();
userDao.delete();
}
}
- 運行結果

2. 基于注解開發AspectJ【***】
??注意:一定要在applicationContext.xml中配置<aop:aspectj-autoproxy></aop:aspectj-autoproxy>才能讓aop起作用,
AspectJ通知注解【***】
| 注解名稱 | 描 述 |
|---|---|
| @Aspect | 用于定義一個切面,注解在切面類上 |
| @Pointcut | 用于定義切入點運算式,在使用時,需要定義一個切入點方法,該方法是一個回傳值void,且方法體為空的普通方法 |
| @Before | 用于定義前置通知,在使用時,通常為其指定value屬性值,該值可以是已有的切入點,也可以直接定義切入點運算式 |
| @AfterReturning | 用于定義 后置回傳通知,在使用時,通常為其指定value屬性值,該值可以是已有的切入點,也可以直接定義切入點運算式 |
| @Around | 用于定義 環繞通知,在使用時,通常為其指定value屬性值,該值可以是已有的切入點,也可以直接定義切入點運算式 |
| @AfterThrowing | 用于定義例外通知,在使用時,通常為其指定value屬性值,該值可以是已有的切入點,也可以直接定義切入點運算式,另外,還有一個throwing屬性用于訪問目標方法拋出的例外,該屬性值與例外通知方法中同名的形參一致 |
| @After | 用于定義后置(最終)通知,在使用時,通常為其指定value屬性值,該值可以是已有的切入點,也可以直接定義切入點運算式 |
連接點(JoinPoint)【***】
程式運行中的一些時間點, 例如一個方法的執行, 或者是一個例外的處理(和方法有關的前前后后都是連接點)
| JoinPoint物件方法 | 描述 |
|---|---|
| Signature getSignature() | 獲取封裝了署名資訊的物件,在該物件中可以獲取到目標方法名,所屬類的Class等資訊 |
| Object getTarget() | 獲取被代理的物件 |
| Object getThis() | 獲取代理物件 |
| Object[] getArgs() | 獲取傳入目標方法的引數物件(輸入的引數串列) |
| joinpoint.proceed() | 在環繞通知around中使用,用于啟動目標方法執行的(環繞通知=前置+目標方法執行+后置通知) |
| joinPoint.getSignature().getName() | 獲取目標物件被增強的方法 |
案例
- pom.xml匯入依賴
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
- 創建被代理類
public interface UserDao {
public void save();
public void delete();
}
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
//int i = 100/0;//例外拋出 虛擬機終止程式運行
System.out.println("save 保存 ......");
}
@Override
public void delete() {
System.out.println("delete 洗掉 ......");
}
}
- 創建切面類
// @Component配置 啟動容器會實體化類 名字首字母小寫myAspect
// @Aspect配置切面
@Aspect
@Component
public class MyAspect {
/* 配置切點 - pointcut切點
execution(回傳值型別 包名.類名.方法名(引數))
(..)代表任意引數
*/
@Pointcut("execution(* com.xgf.aop.aspectj.annotation.*.*(..))")
public void mycut(){// 切點的id
}
// 通知 advice
//@Before("mycut()") //當有多個值時用value 只有一個屬性的時候直接寫
@Before(value="mycut()")
public void before(JoinPoint joinPoint){
//JoinPoint物件封裝了SpringAop中切面方法的資訊,在切面方法中添加JoinPoint引數,就可以獲取到封裝了該方法資訊的JoinPoint物件.
// 獲取被代理物件
joinPoint.getTarget();
// 目標物件被增強的方法
joinPoint.getSignature().getName();
System.out.println("前置通知,用于權限控制 被代理物件: "+ joinPoint.getTarget()+" ----方法名methodName---"+joinPoint.getSignature().getName());
}
@AfterReturning("mycut()")
public void afterReturning(JoinPoint joinPoint){
System.out.println("后置回傳通知,清除操作過的檔案 被代理物件:"+ joinPoint.getTarget()+" ----方法名methodName---"+joinPoint.getSignature().getName());
}
@Around("mycut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環繞通知,方法執行之前,開啟事務");
joinPoint.proceed();//啟動目標方法執行
System.out.println("環繞通知,方法執行之后,關閉事務");
}
@AfterThrowing(value = "mycut()",throwing = "e")
public void afterThrowing(Throwable e) throws Throwable {
System.out.println("例外通知:方法出現例外呼叫,處理例外"+e.getMessage());
}
@After("mycut()")
public void after(JoinPoint joinPoint) {
System.out.println("最終通知 管理資料庫連接等清理作業");
}
}
- 創建applicationContext.xml組態檔
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>一要有定,不然不起作用!
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<!--基于注解開發 掃描包-->
<!-- 容器啟動的時候 加載組態檔xml 讀取com.xgf.aop.aspectj.annotation包識別注解 -->
<context:component-scan base-package="com.xgf.aop.aspectj.annotation"/>
<!--使aop起作用-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
- 撰寫測驗類
public class AspectJAnnotationTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("com/xgf/aop/aspectj/annotation/applicationContext.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
//呼叫方法
userDao.save();
userDao.delete();
}
}
- 執行結果

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/152308.html
標籤:其他
