Spring——AOP實現

小?同學發表於2020-08-11

Spring實現AOP

1、什麼是 AOP

AOP (Aspect Orient Programming),直譯過來就是 面向切面程式設計。AOP 是一種程式設計思想,是物件導向程式設計(OOP)的一種補充。物件導向程式設計將程式抽象成各個層次的物件,而面向切面程式設計是將程式抽象成各個切面。

img

從該圖可以很形象地看出,所謂切面,相當於應用物件間的橫切點,我們可以將其單獨抽象為單獨的模組。

2、AOP的實現

【重要】:使用AOP需要匯入依賴包

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
</dependencies>

方式一:使用Spring的API介面【主要SpringAPI介面實現】

  • xml配置:

    <!--註冊bean-->
    <bean id="userService" class="com.spong.demo03.UserServiceImpl"/>
    <bean id="logBefore" class="com.spong.demo03.LogBefore"/>
    <bean id="logAfter" class="com.spong.demo03.LogAfter"/>
    
    <!--方式一: 使用原生的Spring API介面-->
    <!--配置aop:需要匯入aop的約束-->
    <aop:config>
        切入點:expression:表示式,execution(要執行的位置: * * * ...)
        <aop:pointcut id="pointcut" expression="execution(* com.spong.demo03.UserServiceImpl.*(..))"/>
    
        <!--執行環繞增加-->
        <aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
    </aop:config>
    
  • 需要切入的類(實現aop包下的介面MethodBeforeAdvice、AfterReturningAdvice等)

    public class LogBefore implements MethodBeforeAdvice {
    
        /**
         *
         * @param method 要執行的目標物件的方法
         * @param objects 方法引數
         * @param o 目標物件
         * @throws Throwable
         */
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println(o.getClass().getName()+"的"+method.getName()+"執行");
        }
    }
    
    public class LogAfter implements AfterReturningAdvice {
    
        /**
         *
         * @param returnValue 方法執行後的返回值
         * @param method
         * @param args
         * @param target
         * @throws Throwable
         */
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println(target.getClass().getName()+"的"+method.getName()+"方法執行,返回值為"+returnValue);
        }
    }
    

方式二:自定義類來實現AOP【主要是切面定義】

  • 自定義類:

    public class Diy {
    
        public void logBefore(){
            System.out.println("方法執行前");
        }
    
        public void logAfter(){
            System.out.println("方法執行後");
        }
    }
    
  • xml配置:

    <!--方式二: 自定義類-->
    <bean id="diy" class="com.spong.demo03.Diy"/>
    
    <aop:config>
        <aop:aspect ref="diy">
            <aop:pointcut id="pointcut" expression="execution(* com.spong.demo03.UserServiceImpl.*(..))"/>
            <aop:before method="logBefore" pointcut-ref="pointcut"/>
            <aop:after method="logAfter" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
    

方式三:使用註解實現

  • 使用註解實現的切面類:

    //使用註解實現AOP
    @Aspect //標註為一個切面
    @Component //注入bean
    public class AnnotationPointCut {
        
        //設定切入點
        @Pointcut("execution(* com.spong.demo03.UserServiceImpl.*(..))")
        private void pointCut(){}
    
        @Before("pointCut()")
        public void logBefore(){
            System.out.println("方法執行前");
        }
    
        @After("pointCut()")
        public void logAfter(){
            System.out.println("方法執行後");
        }
    
        @Around("pointCut()")   //環繞增強,我們可以給定一個引數,代表我們要獲取處理切入的點;
        public void around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("環繞前");
            System.out.println(joinPoint.getSignature());   //獲得簽名(呼叫了哪個類的哪個方法)
            Object proceed = joinPoint.proceed();
            System.out.println("環繞後");
        }
    
    }
    
  • xml配置:

    <!--開啟aop註解支援-->
    <aop:aspectj-autoproxy/>
    
    <!--開啟註解支援-->
    <context:component-scan base-package="com.spong.demo03"/>
    <context:annotation-config></context:annotation-config>
    
  • 測試類

    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            //這裡返回的是一個代理類例項,代理類也是實現了UserService介面
            UserService userService = context.getBean("userService", UserService.class);
            userService.add();
        }
    }
    
  • 測試結果:

    環繞前
    void com.spong.demo03.UserService.add()
    方法執行前
    add
    方法執行後
    環繞後
    

切入點表示式execution (* com.sample.service..*. *(..))解析:

整個表示式可以分為五個部分:

1、execution()::表示式主體。

2、第一個*號:表示返回型別, *號表示所有的型別。

3、包名:表示需要攔截的包名,後面的兩個句點表示當前包和當前包的所有子包,com.sample.service包、子孫包下所有類的方法。

4、第二個號:表示類名,號表示所有的類。

5、(..):最後這個星號表示方法名,號表示所有的方法,後面括弧裡面表示方法的引數,兩個句點表示任何引數

相關文章