Spring-AOP概念及使用教程

Spring-AOP

1、AOP 基本概念

​ (1)面向切面編程(方面),利用 AOP 可以對業務邏輯的各個部分進行隔離,從而使得 業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。

​ (2)通俗描述:不通過修改源代碼方式,在主幹功能裏面添加新功能

​ (3)使用登錄例子說明 AOP

在這裏插入圖片描述

2、AOP(底層原理)

​ a)AOP 底層使用動態代理 ,動態代理有兩種情況:

第一種 有接口情況,使用 JDK 動態代理 ;創建接口實現類代理對象,增強類的方法
在這裏插入圖片描述

第二種 沒有接口情況,使用 CGLIB 動態代理;創建子類的代理對象,增強類的方法
在這裏插入圖片描述

3、AOP(JDK 動態代理)

​ 1)使用 JDK 動態代理,使用 Proxy 類裏面的方法創建代理對象

調用 newProxyInstance 方法,方法有三個參數:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

​ 第一參數,類加載器

​ 第二參數,增強方法所在的類,這個類實現的接口,支持多個接口

​ 第三參數,實現這個接口 InvocationHandler,創建代理對象,寫增強的部分

​ 2)編寫 JDK 動態代理代碼

//(1)創建接口,定義方法
public interface UserDao {
 public int add(int a,int b);
 public String update(String id);
}
//(2)創建接口實現類,實現方法
public class UserDaoImpl implements UserDao {
 @Override
 public int add(int a, int b) {
 return a+b;
 }
 @Override
 public String update(String id) {
 return id;
 }
}
//(3)使用 Proxy 類創建接口代理對象
public class JDKProxy {
 public static void main(String[] args) {
 //創建接口實現類代理對象
 Class[] interfaces = {UserDao.class};
 UserDaoImpl userDao = new UserDaoImpl(); 
/** 第一參數,類加載器 
	第二參數,增強方法所在的類,這個類實現的接口,(支持多個接口)
	第三參數,實現這個接口 InvocationHandler,創建代理對象,寫增強的部分  */
 UserDao dao =(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,
					new UserDaoProxy(userDao));
 int result = dao.add(1, 2);
 System.out.println("result:"+result);
 }
}

//創建代理對象代碼
class UserDaoProxy implements InvocationHandler {
 //1 把創建的是誰的代理對象,把誰傳遞過來
 //有參數構造傳遞
 private Object obj;
 public UserDaoProxy(Object obj) {
 this.obj = obj;
 }
 //增強的邏輯
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 //方法之前
 System.out.println("方法之前執行...."+method.getName()+" :傳遞的參數..."+ Arrays.toString(args));
 //被增強的方法執行
 Object res = method.invoke(obj, args);
 //方法之後
 System.out.println("方法之後執行...."+obj);
 return res;
 }
}

4、AOP(術語)

​ a)連接點:類裏面哪些方法可以被增強,這些方法稱爲連接點

​ b)切入點:實際被真正增強的方法稱爲切入點

​ c)通知(增強):實際增強的邏輯部分稱爲通知,且分爲以下五種類型:

​ 1)前置通知 2)後置通知 3)環繞通知 4)異常通知 5)最終通知

​ d)切面:把通知應用到切入點過程

5、AOP操作

​ a)Spring 框架一般都是基於 AspectJ 實現 AOP 操作,AspectJ 不是 Spring 組成部分,獨立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,進行 AOP 操作

​ b)基於 AspectJ 實現 AOP 操作:1)基於 xml 配置文件實現 (2)基於註解方式實現(使用)

​ c)引入相關jar包

​ d)切入點表達式,如下:

1)切入點表達式作用:知道對哪個類裏面的哪個方法進行增強 
(2)語法結構: execution([權限修飾符] [返回類型] [類全路徑] [方法名稱]([參數列表]) )3)例子如下:
    例 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.*.* (..))

6、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、進行通知的配置-->
<?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.atguigu.spring5.aopanno"></context:component-scan>

    <!-- 開啓Aspect生成代理對象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
//增強的類
@Component
@Aspect  //生成代理對象
public class UserProxy {}

//被增強的類
@Component
public class User {}

//4、配置不同類型的通知
@Component
@Aspect  //生成代理對象
public class UserProxy {
      //相同切入點抽取
    @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo() {

    }

    //前置通知
    //@Before註解表示作爲前置通知
    @Before(value = "pointdemo()")//相同切入點抽取使用!
    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("環繞之後.........");
    }
}

7、有多個增強類對同一個方法進行增強,設置增強類優先級

//(1)在增強類上面添加註解 @Order(數字類型值),數字類型值越小優先級越高
@Component
@Aspect
@Order(1)
public class PersonProxy{ }

8、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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章