1、操作術語
1.1、連接配接點
類裡面哪些方法可以被增強、這些方法被稱為連接配接點。比如:使用者控制層有登入、注冊、修改密碼、修改資訊等方法。假如隻有登入類和注冊類可以被增強,登入和注冊方法就稱為連接配接點
1.2、切入點
實際被真正增強的方法,稱為切入點。假如登入方法被正真增強(登陸前做些權限驗證之類的、假設原始方法隻是查詢資料庫、無權限認證過程)、登入方法又稱為切入點。
1.3、通知(增強)
實際增強的邏輯部分稱為通知(增強)。你編寫的新的業務邏輯、比如在登入前進行的權限認證操作。
通知有多種類型
- 前置通知
- 後置通知
- 環繞通知
- 異常通知
- 最終通知
1.4、切面
把通知應用到切入點過程。你編寫的業務邏輯(通知)如何加入到之前的方法(切入點)
2、準備工作和如何使用
友情提示:如果直接建立spring項目、則不需要進行這一步
2.1
2.1 jar包引入
1、Spring 架構一般都是基于 AspectJ 實作 AOP 操作
- AspectJ 不是 Spring 組成部分,獨立 AOP 架構,一般把 AspectJ 和 Spirng 架構一起使用,進行 AOP 操作
2、基于 AspectJ 實作 AOP 操作
- 基于 xml 配置檔案實作
- 基于注解方式實作(使用)
3、在項目工程裡面引入 AOP 相關依賴
2.2、切入點表達式(具體使用)
(1)切入點表達式作用:知道對哪個類裡面的哪個方法進行增強
(2)文法結構: execution([權限修飾符] [傳回類型] [類全路徑] [方法名稱]([參數清單]) )
例子
舉例 1:對 com.zyz.dao.BookDao 類裡面的 add 進行增強
execution(* com.zyz.dao.BookDao.add(..))
舉例 2:對 com.zyz.dao.BookDao 類裡面的所有的方法進行增強
execution(* com.zyz.dao.BookDao.* (..))
舉例 3:對 com.zyz.dao 包裡面所有類,類裡面所有方法進行增強
execution(* com.zyz.dao.*.* (..))
3、代碼實戰
3.1 User .java
一個類裡邊的基本方法。 使用注解 @Component
建立 User 對象。
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/20 22:16
*/
@Component
public class User {
public void add(){
// int a = 1/0;
System.out.println("add......");
}
}
3.2 UserProxy .java
1、代理類中進行方法的增強。
2、使用注解
@Component
建立 UserProxy 對象。
3、在增強類上面添加注解 @Aspec。
4、增強類的裡面,在作為通知方法上面添加通知類型注解,使用切入點表達式配置
/**
* 增強的類
* @author Lenovo
* @version 1.0
* @data 2022/10/20 22:19
*/
@Component
@Aspect//生成代理對象
public class UserProxy {
/**
* 1、前置通知
*/
@Before(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void before(){
System.out.println("before。。。。。。");
}
/**
* 2、後置通知
*/
@AfterReturning(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void afterReturnning(){
System.out.println("afterReturnning。。。。。。");
}
/**
* 3、最終通知
*/
@After(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void after(){
System.out.println("after。。。。。。");
}
/**
* 4、異常通知
*/
@AfterThrowing(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing。。。。。。");
}
/**
* 5、環繞通知
* @param proceedingJoinPoint
* @throws Throwable
*/
@Around(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環繞之前。。。。。。。");
//被增強的方法執行
proceedingJoinPoint.proceed();
System.out.println("環繞之後。。。。。。。");
}
}
3.3 bean.xml
<?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.zyz.spring5.aop"></context:component-scan>
<!-- 開啟 Aspect 生成代理對象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3.4 測試類
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/20 22:38
*/
public class Test {
@org.junit.Test
public void testDemo(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
3.5 測試結果
4、優化代碼
4.1 相同的切入點抽取
仔細看代碼不難發現、耦合性很高。比如增強的方法類的位置移動。那麼所有增強的表達式中的路徑也要一個一個改動(3.2 UserProxy.java)
相同的切入點抽取、達到複用的效果。可以隻需要改動少量的代碼、完成相同的事情。便于後期的維護
/**
* 增強的類
* @author Lenovo
* @version 1.0
* @data 2022/10/20 22:19
*/
@Component
@Aspect//生成代理對象
public class UserProxy {
/**
* 相同切入點抽取
*/
@Pointcut(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void pointDemo(){}
/**
* 1、前置通知
*/
@Before(value = "pointDemo()")
public void before(){
System.out.println("before。。。。。。");
}
/**
* 2、後置通知
*/
@AfterReturning(value = "pointDemo()")
public void afterReturnning(){
System.out.println("afterReturnning。。。。。。");
}
/**
* 3、最終通知
*/
@After(value = "pointDemo()")
public void after(){
System.out.println("after。。。。。。");
}
/**
* 4、異常通知
*/
@AfterThrowing(value = "pointDemo()")
public void afterThrowing(){
System.out.println("afterThrowing。。。。。。");
}
/**
* 5、環繞通知
* @param proceedingJoinPoint
* @throws Throwable
*/
@Around(value = "pointDemo()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環繞之前。。。。。。。");
//被增強的方法執行
proceedingJoinPoint.proceed();
System.out.println("環繞之後。。。。。。。");
}
}
4.2 有多個增強類多同一個方法進行增強,設定增強類優先級
@Order(1)
數字越小優先級越高
@Component
@Aspect
@Order(1)
public class UserProxy1
建立一個增強類1
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/22 18:50
*/
@Component
@Aspect
@Order(1)
public class UserProxy1 {
/**
* 1、前置通知
*/
@Before(value = "execution(* com.zyz.spring5.aop.User.add(..))")
public void before(){
System.out.println("我的優先級高哦、我先執行。before。。。。。。");
}
}
之前的增強類也添加一個優先級
@Component
@Aspect//生成代理對象
@Order(3)
public class UserProxy {
測試結果
5、完全注解開發
5.1 新增一個配置類
ConfigAop.java
/**
* @author Lenovo
* @version 1.0
* @data 2022/10/22 18:58
*/
@Configuration
@ComponentScan(basePackages = {"com.zyz"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
5.2 測試方式改動
之前讀取的是配置檔案。現在要讀取配置類
@org.junit.Test
public void testDemo1(){
//加載配置類
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
User user = context.getBean("user", User.class);
user.add();
}
測試結果不變
目錄結構