Spring AOP 面向切面
- 什麼是 AOP
- AOP(底層原理)
- AOP(JDK 動态代理)
- AOP 術語
- AOP 操作
- AOP 操作(AspectJ 注解)
- AOP 操作(AspectJ 配置檔案)
什麼是 AOP
(1)面向切面程式設計(方面),利用 AOP 可以對業務邏輯的各個部分進行隔離,進而使得 業務邏輯各部分之間的耦合 度降低,提高程式的可重用性,同時提高了開發的效率。
(2)通俗描述:不通過修改源代碼方式,在主幹功能裡面添加新功能
(3)使用登入例子說明 AOP

AOP(底層原理)
1、AOP 底層使用動态代理
(1)有兩種情況動态代理
第一種 有接口情況,使用 JDK 動态代理
⚫ 建立接口實作類代理對象,增強類的方法
第二種 沒有接口情況,使用 CGLIB 動态代理
⚫ 建立子類的代理對象,增強類的方法
AOP(JDK 動态代理)
1、使用 JDK 動态代理,使用 Proxy 類裡面的方法建立代理對象
(1)調用 newProxyInstance 方法
方法有三個參數:
第一參數,類加載器
第二參數,增強方法所在的類,這個類實作的接口,支援多個接口
第三參數,實作這個接口 InvocationHandler,建立代理對象,寫增強的部分
2、編寫 JDK 動态代理代碼
package day01;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy {
public static void main(String[] args) {
UserDaoImpl userDao =new UserDaoImpl();
// 建立
Class [] inter = {UserDao.class};
UserDao userDao1 = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), inter, new UserDaoProxy(userDao));
int add = userDao1.add(1, 3);
System.out.println(add);
}
}
class UserDaoProxy implements InvocationHandler{
private Object object;
public UserDaoProxy(Object object){
this.object =object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("=====方法前====");
Object invoke = method.invoke(object, args);
System.out.println("=======方法後======="+invoke);
return invoke;
}
}
AOP 術語
-
連接配接點
裡面有哪些方法可以被增強,這些方法被稱為連接配接點。
-
切入點
實際被真正增強的方法
-
通知
(1)實際 增強的邏輯部分稱為 通知(增強)
(2)通知有做種類型
前置通知
後置通知
環繞通知
異常通知
最終通知
-
切面
是動作,是一個過程
(1)把通知 應用到 切入點 的過程
AOP 操作
-
Spring 架構一般都是基于 AspectJ 實作 AOP 操作
(1)AspectJ 不是 Spring 組成部分,獨立 AOP 架構,一般把 AspectJ 和 Spirng 架構一起使用,進行 AOP 操作
-
基于 AspectJ 實作 AOP 操作
(1)基于 xml 配置檔案實作
(2)基于注解方式實作(使用)
- 在項目工程裡面引入 AOP 相關依賴
-
切入點表達式
(1)切入點表達式作用:知道對哪個類裡面的哪個方法進行增強
(2)文法結構: execution([權限修飾符] [傳回類型] [類全路徑] 方法名稱 )
舉例 1:對 com.atguigu.dao.BookDao 類裡面的 add 進行增強 execution(* com.atguigu.dao.BookDao.add(..)) 舉例 2:對 com.atguigu.dao.BookDao 類裡面的所有的方法進行增強 execution(* com.atguigu.dao.BookDao.* (..)) 舉例 3:對 com.atguigu.dao 包裡面所有類,類裡面所有方法進行增強 execution(* com.atguigu.dao.*.* (..))
AOP 操作(AspectJ 注解)
1、建立類,在類裡面定義方法
public class User {
public void add() {
System.out.println("add.......");
} }
2、建立增強類(編寫增強邏輯)
(1)在增強類裡面,建立方法,讓不同方法代表不同通知類型
//增強的類
public class UserProxy {
public void before() {//前置通知
System.out.println("before......");
} }
3、進行通知的配置
(1)在 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 basepackage="com.atguigu.spring5.aopanno"></context:component-scan>
(2)使用注解建立 User 和 UserProxy 對象
(3)在增強類上面添加注解 @Aspect
//增強的類
@Component
@Aspect //生成代理對象
public class UserProxy {
(4)在 spring 配置檔案中開啟生成代理對象
<!-- 開啟 Aspect 生成代理對象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同類型的通知
(1)在增強類的裡面,在作為通知方法上面添加通知類型注解,使用切入點表達式配置
//增強的類
@Component
@Aspect //生成代理對象
public class UserProxy {
//前置通知
//@Before 注解表示作為前置通知
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void before() {
System.out.println("before.........");
}
//後置通知(傳回通知)
@AfterReturning(value = "execution(*
com.atguigu.spring5.aopanno.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning.........");
}
//最終通知
@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void after() {
System.out.println("after.........");
}
//異常通知
@AfterThrowing(value = "execution(*
com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
//環繞通知
@Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws
Throwable {
System.out.println("環繞之前.........");
//被增強的方法執行
proceedingJoinPoint.proceed();
System.out.println("環繞之後.........");
} }
5、相同的切入點抽取
//相同切入點抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointdemo() {
}
//前置通知
//@Before 注解表示作為前置通知
@Before(value = "pointdemo()")
public void before() {
System.out.println("before.........");
}
6、有多個增強類多同一個方法進行增強,設定增強類優先級
(1)在增強類上面添加注解 @Order(數字類型值),數字類型值越小優先級越高
@Component
@Aspect
@Order(1)
public class PersonProxy
7、完全使用注解開發 (1)建立配置類,不需要建立 xml 配置檔案
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
AOP 操作(AspectJ 配置檔案)
1、建立兩個類,增強類和被增強類,建立方法
2、在 spring 配置檔案中建立兩個類對象
<!--建立對象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book">
</bean> <bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
3、在 spring 配置檔案中配置切入點
<!--配置 aop 增強--> <aop:config>
<!--切入點-->
<aop:pointcut id="p" expression="execution(*
com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增強作用在具體的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config