天天看點

【spring】AOP介紹底層原理AOP術語ASpectJ

介紹

AOP 的全稱是“Aspect Oriented Programming”,譯為“面向切面程式設計”

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

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

(3)使用登入例子說明 AOP

【spring】AOP介紹底層原理AOP術語ASpectJ

底層原理

代理模式-動态代理

(1)有兩種情況動态代理

JDK 動态代理

第一種 有接口情況,使用 JDK 動态代理

建立接口實作類代理對象,增強類的方法

【spring】AOP介紹底層原理AOP術語ASpectJ

反射

(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};  
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,   
new InvocationHandler() {  
// @Override  
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
// return null;  
// }  
// });  
            UserDaoImpl userDao = new UserDaoImpl();  
            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;  
         }  
      }
           

CGLIB 動态代理

第二種 沒有接口情況,使用 CGLIB 動态代理

建立子類的代理對象,增強類的方法

【spring】AOP介紹底層原理AOP術語ASpectJ

AOP術語

【spring】AOP介紹底層原理AOP術語ASpectJ

ASpectJ

概述

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

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

2、基于 AspectJ 實作 AOP 操作 ,有兩種方式:

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

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

3、在項目工程裡面引入 AOP 相關依賴

【spring】AOP介紹底層原理AOP術語ASpectJ

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.*.* (..))

注解

1、建立類,在類裡面定義方法

@Component
public class User {  
    public void add() {  
        System.out.println("add.......");  
    }  
}
           

2.建立增強類(編寫增強邏輯)

(1)在增強類裡面,建立方法,讓不同方法代表不同通知類型

//增強的類  
@Component
@Aspect
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 base-package="com.atguigu.spring5.aopanno"></context:component-scan>

           

(2)使用注解建立 User 和 UserProxy 對象

(3)在增強類上面添加注解 @Aspect

(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("環繞之後.........");  
    }  
}
           
【spring】AOP介紹底層原理AOP術語ASpectJ

spring5.2.9順序為:

環繞之前…

before…

add…

afterReturning…

after…

環繞之後…

after和finally類似,有無異常都執行;若有異常,就會執行afterthrowing…,不會執行afterreturning

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 {  
}
           

xml配置

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>