天天看點

Spring之AOP原理及多種實作方式

​​AOP概念​​

​​AOP的實作​​

​​方式1:使用Spring的API接口​​

​​ 1:編寫一個類,實作相關的接口​​

​​2:核心配置檔案​​

​​3:單元測試​​

​​方式2:自定義實作AOP​​

​​1:自定義一個類​​

​​2:核心配置檔案​​

​​3:單元測試​​

​​方式3:使用注解實作​​

​​1:開啟AOP注解支援​​

​​2:自定義切面類使用注解​​

​​3:單元測試​​

​​4:各種切面注解測試​​

AOP概念

百度百科:

在軟體業,AOP為Aspect Oriented Programming的縮寫,意為:​​面向切面程式設計​​​,通過​​預編譯​​​方式和運作期間動态代理實作程式功能的統一維護的一種技術。AOP是​​OOP​​​的延續,是軟體開發中的一個熱點,也是​​Spring​​​架構中的一個重要内容,是​​函數式程式設計​​​的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的​​耦合度​​降低,提高程式的可重用性,同時提高了開發的效率。

舉個栗

Spring之AOP原理及多種實作方式
Spring之AOP原理及多種實作方式
Spring之AOP原理及多種實作方式

AOP的實作

要使用Spring的AOP織入,就得使用相關的包,這裡使用Maven導入
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>      
我們舉例的業務service層和實作類
package com.lingaolu.service;

/**
 * @author 林高祿
 * @create 2020-11-10-10:43
 */
public interface StudentService {

    void mathod1();

    String mathod2();


}
package com.lingaolu.impl;

import com.lingaolu.service.StudentService;

/**
 * @author 林高祿
 * @create 2020-11-10-10:46
 */
public class StudentServiceImpl implements StudentService {

    @Override
    public void mathod1() {
        System.out.println("通路mathod1");
    }

    @Override
    public String mathod2() {
        System.out.println("通路mathod2");
        return "方法2傳回值";
    }
}      

方式1:使用Spring的API接口

 1:編寫一個類,實作相關的接口

Spring之AOP原理及多種實作方式
package com.lingaolu.system;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @author 林高祿
 * @create 2020-11-10-10:54
 */
public class MyLog implements MethodBeforeAdvice,AfterReturningAdvice {

    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"執行前aa......");
    }

    @Override
    public void afterReturning(Object returnVar, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"執行後......,傳回值:"+returnVar);
    }
}      

2:核心配置檔案

Spring之AOP原理及多種實作方式
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <!--注冊bean-->
        <bean id="studentService" class="com.lingaolu.impl.StudentServiceImpl"/>
        <bean id="myLog" class="com.lingaolu.system.MyLog"/>
        <!--配置AOP,需要導入AOP限制-->
        <aop:config>
            <!--切入點,expression表達式:execution(* * * * *)-->
            <!-- 5個*的位置分别表示,傳回值,包,類,方法參數,更多的可以去查資料 -->
            <!-- 我們這裡的配置,表示這個類的所有方法,..表示任意參數類型 -->
            <aop:pointcut id="pointcut" expression="execution(* com.lingaolu.impl.StudentServiceImpl.*(..))"/>
            <!-- 為切入點執行增加 -->
            <aop:advisor advice-ref="myLog" pointcut-ref="pointcut"/>
        </aop:config>
</beans>      

3:單元測試

Spring之AOP原理及多種實作方式

方式2:自定義實作AOP

1:自定義一個類

Spring之AOP原理及多種實作方式
package com.lingaolu.system;

/**
 * @author 林高祿
 * @create 2020-11-10-10:54
 */
public class MyLog {

   public void myBefore(){
       System.out.println("調用方法前......");
   }

   public String myAfter(){
       System.out.println("調用方法後......");
       return "調用方法後傳回值";
   }
}      

2:核心配置檔案

Spring之AOP原理及多種實作方式
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <!--注冊bean-->
        <bean id="studentService" class="com.lingaolu.impl.StudentServiceImpl"/>
        <bean id="myLog" class="com.lingaolu.system.MyLog"/>
        <!--配置AOP,需要導入AOP限制-->
        <aop:config>
            <!--切入點,expression表達式:execution(* * * * *)-->
            <!-- 5個*的位置分别表示,傳回值,包,類,方法參數,更多的可以去查資料 -->
            <!-- 我們這裡的配置,表示這個類的所有方法,..表示任意參數類型 -->
            <aop:pointcut id="pointcut" expression="execution(* com.lingaolu.impl.StudentServiceImpl.*(..))"/>
            <!-- 配置切面類 -->
            <aop:aspect ref="myLog">
                <!-- 切面調用方法前,調用切面類的myBefor方法,所作用于的切面pointcut -->
                <aop:before method="myBefore" pointcut-ref="pointcut"/>
                <!-- 切面調用方法後,調用切面類的myAfter方法,所作用于的切面pointcut -->
                <aop:after method="myAfter" pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config>
</beans>      

3:單元測試

Spring之AOP原理及多種實作方式

方式3:使用注解實作

1:開啟AOP注解支援

Spring之AOP原理及多種實作方式
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

        <!--注冊bean-->
        <bean id="studentService" class="com.lingaolu.impl.StudentServiceImpl"/>
        <bean id="myLog" class="com.lingaolu.system.MyLog"/>
        <!--開啟AOP注解支援,proxy-target-class預設為false,表示JDK方式實作動态代理,true表示cglib方式-->
        <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>      

2:自定義切面類使用注解

Spring之AOP原理及多種實作方式
package com.lingaolu.system;

import org.aspectj.lang.annotation.*;

/**
 * @author 林高祿
 * @create 2020-11-10-10:54
 */
@Aspect
public class MyLog {

    @Before("execution(* com.lingaolu.impl.StudentServiceImpl.*(..))")
    public void myBefore(){
        System.out.println("調用方法前......");
    }

    @After("execution(* com.lingaolu.impl.StudentServiceImpl.*(..))")
    public String myAfter(){
        System.out.println("調用方法後......");
        return "調用方法後傳回值";
    }
}      

3:單元測試

Spring之AOP原理及多種實作方式

4:各種切面注解測試

Spring之AOP原理及多種實作方式
package com.lingaolu.system;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;

/**
 * @author 林高祿
 * @create 2020-11-10-10:54
 */
@Aspect
public class MyLog {

    @Before("execution(* com.lingaolu.impl.StudentServiceImpl.*(..))")
    public void myBefore(){
        System.out.println("調用方法前......");
    }

    @After("execution(* com.lingaolu.impl.StudentServiceImpl.*(..))")
    public String myAfter(){
        System.out.println("調用方法後......");
        return "調用方法後傳回值";
    }

    /**
     * 在環繞增強中,我們可以給定一個參數,代表我們要擷取處理切入的點
     * @param pj    擷取處理切入的點
     */
    @Around("execution(* com.lingaolu.impl.StudentServiceImpl.*(..))")
    public void Around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("調用方法環繞......");
        // 擷取簽名
        Signature signature = pj.getSignature();
        System.out.println(signature);
        // 方法執行
        Object proceed = pj.proceed();
        System.out.println(proceed);
    }
}      
測試結果符合
Spring之AOP原理及多種實作方式