1. 程式人生 > 其它 >@AspectJ註解方式的aop

@AspectJ註解方式的aop

@AspectJ註解方式的aop

第一步:匯入依賴
 <dependencies>


<!-- 引入spring 依賴 作為CGLIB的依賴 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.12</version>
</dependency>

<!-- aspect -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!--spring 整合測試-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.7</version>
<scope>test</scope>
</dependency>
</dependencies>
第二步:開啟@aspect註冊 和包掃描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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">


<!--使用bean 註解掃描 自動開啟註解功能
*就是如果某個類上面帶有特定的註解
@Component,@Repository,@Service,@Controller 就會將這個物件作為bean注入到spring容器中
-->
<context:component-scan base-package="com.bird"/>

<!-- 配置aop的aspectj的自動代理:
*自動掃描bean元件中,含有@Aspect的bean 將其作為aop管理 開啟自動代理
-->
<aop:aspectj-autoproxy/>

</beans>
第三步:定義目標物件並注入到spring容器中
public interface ICustomerService {
public void save();
public int find();
public int error();
}
@Component
public class ICustomerServiceImpl implements ICustomerService {
public void save() {
System.out.println("客戶儲存了。。。。。");
}

public int find() {
System.out.println("客戶查詢數量了。。。。。");
return 100;
}

@Override
public int error() {
int a = 1 / 0;
return 0;
}
}
=======上面是基於介面的動態代理========下面是基於類的動態代理=========
@Service
public class ProductService {
public void save() {
System.out.println("商品儲存了。。。。。");
}

public int find() {
System.out.println("商品查詢數量了。。。。。");
return 99;
}
}
第四步:編寫通知類 並注入到spring容器中
package com.bird.advice.annotationaspectjaop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
* @data 2021/11/28 10:03
* @author: bird
* @description: 這個是基於註解的方式定義的通知類
*/
@Component(value = "myAspect") // 將當前類注入到spring容器中
@Aspect //將該類標識為切面類(這裡面有方法進行增強),相當於<aop:aspect ref=”myAspect”> //宣告但前的這個類是通知類 專門用來增強
public class MyAspect {

// 這個是基於介面的
// 切入點:切入點就是攔截方法 意思就是要對哪些方法進行攔截 然後在通知裡面進行攔截
@Pointcut(value = "execution(* com.bird.advice.annotationaspectjaop.targetobject.ICustomerServiceImpl.save(..))")
public void myPointcut() {
}

// 這個是基於類 進行切入點的
@Pointcut(value = "execution(* com.bird.advice.annotationaspectjaop.targetobject.ProductService.save(..))")
public void mypointcut2() {
}

@Pointcut(value = "execution(* com.bird.advice.annotationaspectjaop.targetobject.ProductService.find(..))")
public void myPointcut3() {
}

@Pointcut(value = "execution(* com.bird.advice.annotationaspectjaop.targetobject.ICustomerServiceImpl.find(..))")
public void myPointcut4() {
}

@Pointcut(value = "execution(* com.bird.advice.annotationaspectjaop.targetobject.ICustomerServiceImpl.error(..))")
public void myPointcut5() {

}


// 前置通知 在save方法執行之前 執行的方法
@Before(value = "myPointcut()|| mypointcut2()")
public void before(JoinPoint joinPoint) {
System.out.println("=======前置通知。。。。。");
}


// 後置通知
@AfterReturning(value = "myPointcut()|| mypointcut2()||myPointcut3()", returning = "returnVal")
public Object afterReturning(JoinPoint joinPoint, Object returnVal) {
System.out.println("++++++++後置通知+++++++++++++:結果" + returnVal);
return returnVal;
}


// 環繞通知
@Around(value = "myPointcut4()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環繞通知------前");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("環繞通知------後");
return proceed;
}

// 丟擲通知 若目標方法執行時 丟擲了異常 那麼就會執行這個增強
@AfterThrowing(value = "myPointcut5()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
StackTraceElement[] stackTrace = ex.getStackTrace();
StackTraceElement stackTraceElement = stackTrace[0];
System.out.println("---丟擲通知......------丟擲的資訊:" + ex.getMessage() + "具體的錯誤行:" + stackTraceElement);
}

// 最終通知 無論目標方法是否發生了異常都會執行下面的方法
@After(value = "myPointcut5()")
public void after(JoinPoint joinPoint) {
System.out.println("--最終通知-----不管是否發生了異常----");
}

}
第五步:測試
package com.bird.jdkproxy;

import com.bird.advice.annotationaspectjaop.targetobject.ICustomerService;
import com.bird.advice.annotationaspectjaop.targetobject.ProductService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* @data 2021/11/28 10:21
* @author: bird
* @description: 這個是基於註解的方式實現的aop
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-annotation-aspect.xml") // 載入指定位置的bean
public class SpringAspectTest {


@Autowired
private ICustomerService customerService;


@Autowired
private ProductService productService;

@Test
public void test() {
// 基於介面
customerService.save();
customerService.find();
System.out.println("******************************************************");
// 基於類
productService.find();
productService.save();

System.out.println("%%%%%%%%%%%%%下面是丟擲異常通知%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
customerService.error();

}
}