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是被代理对象

某个对象需要被动态代理,此对象对应的普通实例对象也是需要被创建的,只是在后续过程中普通实例对象会被替换。

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