步驟:
- 導入相應的依賴
- 開啟注解掃描
- 編寫代理接口
- 被代理接口實作類
- 編寫切面類
- 測試
1. pom.xml加載依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring-11</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<!--導入AOP包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.cglib</groupId>
<artifactId>com.springsource.net.sf.cglib</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
需要的依賴:
- com.springsource.net.sf.cglib-2.1.3.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.9.6.RELEASE.jar
- spring-aspects-5.2.13.RELEASE
2.spring配置檔案
<?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">
<context:component-scan base-package="com.qwy"/>
<!--開啟注解的AOP實作-->
<aop:aspectj-autoproxy/>
</beans>
- content命名空間
- aop命名空間
3. POJO
package com.qwy.bean;
/**
* @author qwy
* @create 2021-04-24 9:46
**/
public class Users {
}
此類純屬為了模拟開發
4.代理接口
package com.qwy.servce;
import com.qwy.bean.Users;
/**
* @author qwy
* @create 2021-04-24 9:46
**/
public interface UsersService {
public void save(Users users);
public void update(Users users);
public void deleteById(Integer id);
public Users getUsersById(Integer id);
}
5. 代理接口實作類(被代理對象)
package com.qwy.servce.impl;
import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.springframework.stereotype.Service;
/**
* @author qwy
* @create 2021-04-24 9:47
**/
@Service("usersService")
public class UsersServiceImpl implements UsersService {
public void save(Users users) {
System.out.println("UsersServiceImpl.save");
}
public void update(Users users) {
System.out.println("UsersServiceImpl.update");
}
public void deleteById(Integer id) {
System.out.println("UsersServiceImpl.deleteById");
}
public Users getUsersById(Integer id) {
System.out.println("UsersServiceImpl.getUsersById");
return new Users();
}
}
隻是為了示範AOP,跟業務無參,這裡隻做了列印,看效果。
- @Service :将被代理對象交給Spring容器管理。
6.切面類
package com.qwy.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author qwy
* @create 2021-04-24 9:29
**/
@Component
@Aspect
public class LogAspect {
@Pointcut("execution(* com.qwy.servce.impl.UsersServiceImpl.update(..))")
private void anyMethod(){}
@Before("anyMethod()")
public void beforeMethod(JoinPoint joinPoint){
//擷取被代理對象的方法名
String name = joinPoint.getSignature().getName();
//擷取被代理對象的參數清單
Object[] args = joinPoint.getArgs();
System.out.println("前置通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}
@AfterReturning(value = "anyMethod()",returning = "result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
//擷取被代理對象的方法名
String name = joinPoint.getSignature().getName();
//擷取被代理對象的參數清單
Object[] args = joinPoint.getArgs();
System.out.println("傳回通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}
@AfterThrowing(value = "anyMethod()",throwing = "e")
public void afterThrowMethod(JoinPoint joinPoint, Exception e){
//擷取被代理對象的方法名
String name = joinPoint.getSignature().getName();
//擷取被代理對象的參數清單
Object[] args = joinPoint.getArgs();
System.out.println("異常通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}
@After("anyMethod()")
public void after(JoinPoint joinPoint){
//擷取被代理對象的方法名
String name = joinPoint.getSignature().getName();
//擷取被代理對象的參數清單
Object[] args = joinPoint.getArgs();
System.out.println("後置通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}
//@Around("anyMethod()")
public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
Object proceed=null;
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
try{
//前置通知
System.out.println("前置通知: 被代理對象的方法: " + name +" , 參數 :" + args);
proceed = joinPoint.proceed();
//傳回通知
System.out.println("傳回通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}catch (Exception e){
System.out.println("異常通知: 被代理對象的方法: " + name +" , 參數 :" + args);
e.printStackTrace();
}finally {
System.out.println("後置通知: 被代理對象的方法: " + name +" , 參數 :" + args);
}
return proceed;
}
}
說明:
- @Component :切面必須是 IOC 中的 bean
- @Aspect :表名該類為切面類
- @Pointcut :定義切面表達式,格式:execution(通路修飾 傳回值 類的全名稱.方法名(參數清單))
- @Before(“anyMethod()”) :表示前置通知,接口的每一個實作類的每一個方法開始之前執行一段代碼,anyMethod表示引用@Pointcut定 義的表達式,當然可以單獨定義。
- @AfterReturning(value = “anyMethod()”,returning = “result”): 表示傳回通知是可以通路到方法的傳回值的!
- @AfterThrowing(value = “anyMethod()”,throwing = “e”):在目标方法出現異常時會執行的代碼.可以通路到異常對象; 且可以指定在出現特定異常時在執行通知代碼。
- @After(“anyMethod()”):在方法執行之後執行的代碼. 無論該方法是否出現異常
- @Around(“anyMethod()”):環繞通知需要攜帶 ProceedingJoinPoint 類型的參數.環繞通知類似于動态代理的全過程: ProceedingJoinPoint 類型的參數可以決定是否執行目标方法.且環繞通知必須有傳回值, 傳回值即為目标方法的傳回值。
7. 測試類
package com.qwy.test;
import com.qwy.bean.Users;
import com.qwy.servce.UsersService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author qwy
* @create 2021-04-24 9:49
**/
public class TestAnnotationAOP {
private ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test1(){
UsersService usersService = ac.getBean("usersService", UsersService.class);
usersService.save(new Users());
usersService.update(new Users());
usersService.deleteById(1);
usersService.getUsersById(1);
}
}
執行結果:
UsersServiceImpl.save
前置通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5
UsersServiceImpl.update
傳回通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5
後置通知: 被代理對象的方法: update , 參數 :[Ljava.lang.Object;@3c947bc5
UsersServiceImpl.deleteById
UsersServiceImpl.getUsersById
需要示範的結果過多。這裡沒有分開示範,大家可以分别示範。