天天看點

Spring5 架構 詳解 ( 二 ) ---- AOP 面向切面什麼是 AOPAOP(底層原理)AOP(JDK 動态代理)AOP 術語AOP 操作AOP 操作(AspectJ 注解)AOP 操作(AspectJ 配置檔案)

Spring AOP 面向切面

  • 什麼是 AOP
  • AOP(底層原理)
  • AOP(JDK 動态代理)
  • AOP 術語
  • AOP 操作
  • AOP 操作(AspectJ 注解)
  • AOP 操作(AspectJ 配置檔案)

什麼是 AOP

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

AOP(底層原理)

1、AOP 底層使用動态代理
		(1)有兩種情況動态代理
				第一種 有接口情況,使用 JDK 動态代理
				⚫ 建立接口實作類代理對象,增強類的方法
           
Spring5 架構 詳解 ( 二 ) ---- AOP 面向切面什麼是 AOPAOP(底層原理)AOP(JDK 動态代理)AOP 術語AOP 操作AOP 操作(AspectJ 注解)AOP 操作(AspectJ 配置檔案)
第二種 沒有接口情況,使用 CGLIB 動态代理
						⚫ 建立子類的代理對象,增強類的方法
           
Spring5 架構 詳解 ( 二 ) ---- AOP 面向切面什麼是 AOPAOP(底層原理)AOP(JDK 動态代理)AOP 術語AOP 操作AOP 操作(AspectJ 注解)AOP 操作(AspectJ 配置檔案)

AOP(JDK 動态代理)

1、使用 JDK 動态代理,使用 Proxy 類裡面的方法建立代理對象

(1)調用 newProxyInstance 方法
			 方法有三個參數:
					第一參數,類加載器
					第二參數,增強方法所在的類,這個類實作的接口,支援多個接口
					第三參數,實作這個接口 InvocationHandler,建立代理對象,寫增強的部分
           
Spring5 架構 詳解 ( 二 ) ---- AOP 面向切面什麼是 AOPAOP(底層原理)AOP(JDK 動态代理)AOP 術語AOP 操作AOP 操作(AspectJ 注解)AOP 操作(AspectJ 配置檔案)

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. 切入點

    實際被真正增強的方法

  3. 通知

    (1)實際 增強的邏輯部分稱為 通知(增強)

    (2)通知有做種類型

    前置通知

    後置通知

    環繞通知

    異常通知

    最終通知

  4. 切面

    是動作,是一個過程

    (1)把通知 應用到 切入點 的過程

AOP 操作

  1. Spring 架構一般都是基于 AspectJ 實作 AOP 操作

    (1)AspectJ 不是 Spring 組成部分,獨立 AOP 架構,一般把 AspectJ 和 Spirng 架構一起使用,進行 AOP 操作

  2. 基于 AspectJ 實作 AOP 操作

    (1)基于 xml 配置檔案實作

    (2)基于注解方式實作(使用)

  3. 在項目工程裡面引入 AOP 相關依賴
  4. 切入點表達式

    (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