AOP解析

AOP bean 準備

1 AOP sample

1.1 創建切面

package com.gientech.aop.xml.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;


import java.util.Arrays;


public class LogUtil {

    public void myPointCut(){}

    public void myPointCut1(){}


    private int start(JoinPoint joinPoint){
        // 獲取方法簽名
        Signature signature = joinPoint.getSignature();
        // 獲取參數信息
        Object[] args = joinPoint.getArgs();
        System.out.println("log----" + signature.getName() + " start execute");
        return 100;
    }

    public static void stop(JoinPoint joinPoint, Object result){
        Signature signature = joinPoint.getSignature();
        System.out.println("log----" + signature.getName() + " execute stop" + result);
    }

    public static void logException(JoinPoint joinPoint, Exception e){
        Signature signature = joinPoint.getSignature();
        System.out.println("log----" + signature.getName() + "throw new excepttion " + e.getMessage());
    }

    public static void logFinally(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        System.out.println("log----" + signature.getName() + " execute over");
    }

    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            System.out.println("log----環繞通知 start: " + signature.getName() + " method start execute, parameter is " + Arrays.asList(args));
            //通過反射的方式調用目標的方法,相當於執行method.invoke(),可以自己修改結果值
            result = pjp.proceed(args);
            System.out.println("log----環繞通知 stop: " + signature.getName() + " method execute over ");
        }catch (Throwable throwable){
            System.out.println("log----環繞異常通知 stop: " + signature.getName() + " 出現異常 ");
            throw throwable;
        }finally {
            System.out.println("log----環繞返回通知 stop: " + signature.getName() + " 方法返回結果是: "  + result);
        }
        return result;
    }

}

1.2 創建業務類

package com.gientech.aop.xml.service;

import org.springframework.stereotype.Service;


public class MyCalculator /* implements Calculator */{


    public Integer add(Integer i, Integer j) throws NoSuchMethodException{
        Integer result = i + j;
        return result;
    }


    public Integer sub(Integer i, Integer j) throws NoSuchMethodException{
        Integer result = i - j;
        return result;
    }

    public Integer mul(Integer i, Integer j) throws NoSuchMethodException{
        Integer result = i * j;
        return result;
    }

    public Integer div(Integer i, Integer j) throws NoSuchMethodException{
        Integer result = i / j;
        return result;
    }

    public Integer show(Integer i){
        System.out.println("show  ......");
        return i;
    }

}

1.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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="logUtil" class="com.gientech.aop.xml.util.LogUtil"></bean>
    <bean id="myCalculator" class="com.gientech.aop.xml.service.MyCalculator"></bean>
    <aop:config>
        <aop:aspect ref="logUtil">
            <aop:pointcut id="myPoint"
                          expression="execution(Integer com.gientech.aop.xml.service.MyCalculator.* (..))"/>
            <aop:around method="around" pointcut-ref="myPoint"></aop:around>
            <aop:around method="start" pointcut-ref="myPoint"></aop:around>
            <aop:before method="start" pointcut-ref="myPoint"></aop:before>
            <aop:after method="logFinally" pointcut-ref="myPoint"></aop:after>
            <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result"></aop:after-returning>
            <aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e"></aop:after-throwing>
        </aop:aspect>
    </aop:config>

 </beans>

1.4 創建啓動類

package com.gientech.aop.xml;

import com.gientech.aop.xml.service.MyCalculator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {
    public static void main(String[] args) throws Exception {
        ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml");
        MyCalculator bean = ac.getBean(MyCalculator.class);
        Integer result = bean.add(1,2);
        System.out.println(result);
    }
}

解析過程中註冊 AspectJAwareAdvisorAutoProxyCreator。
在registerBeanPostProcessors方法中創建 AnnotationAwareAspectJAutoProxyCreator(自動代理創建器)對象。
logutil是切面對象,切面對象不需要被代理,所以logutil不需要被代理。
運行結果如下:
AOPResult

2 AOP BeanDefinition加載過程

當使用spring的aop的時候,需要進行N多個對象的創建,但是在創建過程中需要做很多判斷,判斷當前對象是否需要被代理,而代理之前,需要的advisor對象必須要提前創建好,才能進行後續的判斷。

Aop 標籤對應的類如下:

  • AspectJMethodBeforeAdvice.java: aop:before 標籤對應類
  • AspectJAfterAdvice.java: aop:after 標籤對應類
  • AspectJAfterReturningAdvice.java: after-returning 標籤對應類
  • AspectJAfterThrowingAdvice.java:after-throwing 標籤對應類
  • AspectJAroundAdvice.java: aop:around 標籤對應類
  • AspectJExpressionPointcut.java: 表達式對應的類對象,eg:"execution(Integer com.gientech.aop.xml.service.MyCalculator.* (..))"

AOP BeanDefinition加載過程如圖,
aop解析過程

  • 1 創建AspectJPointAdvisor#0-4,先使用器帶參的構造函數進行對象的創建,但是需要將參數對象準備好,因此要創建內置包含的對象AspectJAroundAdvice
  • 2 創建AspectJAroundAdvice,也需要使用帶參的構造函數進行創建,也需要提前準備好具體的參數對象,包含3個參數對象,分別是MethodLocatingFactoryBean, AspectJExpressionPointcut, SimpleBeanFactoryAwareAspectInstanceFactory。
  • 3 分別創建上述3個對象,上述3個對象的創建過程都是調用無參的構造函數,直接反射生成即可。

自動代理創建器
切面對象不需要被代理
MyCalculator是被代理對象

某個對象需要被動態代理,此對象對應的普通實例對象也是需要被創建的,只是在後續過程中普通實例對象會被替換。

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