Spring之AOP技术 (6)

目录

1. JDK的动态代理:

2. cglib动态代理:

3、Spring AOP 动态代理类生成

 4. 找切面的具体过程

4. 1 找所有切面 

这里需要细说一下:

4.2 找到合格的切面 

 4.3 对切面进行排序

5. 生成代理对象

6、 代理类的调用:此处以jdk代理类为例

核心步骤:

链式调用的核心方法:

调用顺序:


Spring AOP技术是一个难点,缓存、事务都是AOP的一部分。今天,我们就开始AOP的第一讲.

1. JDK的动态代理:

我之前写过一篇关于动态代理的博客《大话设计模式》——读后感 (4)为别人做嫁衣?——动态代理模式(2)_chen_yao_kerr的博客-CSDN博客里面 大概介绍了一下动态代理设计模式。说实话,实际开发中,动态代理用的并不多,除非你是写底层框架的。今天,我们继续说一下动态代理:

package com.zhuguang.jack.proxy;

public interface People {

    public void zhaoduixiang();

    public void yanghaizi() ;
}
package com.zhuguang.jack.proxy;

/*
* 被代理实例
* */
public class Xiaoming implements People {

    //1、在小明双手没有解放之前,小明的父母要帮助小明找到对象

    @Override
    public void zhaoduixiang() {
        System.out.println("我在北京工作,没有时间找对象!!");
    }

    @Override
    public void yanghaizi() {
        System.out.println("努力挣钱, 养孩子");
    }


}
package com.zhuguang.jack.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/*
* 这个是一个增强类,是对目标对象的一个方法增强
* */
public class Parent implements InvocationHandler {

    private People people;

    public Parent(People people) {
        this.people = people;
    }

    /*
    * 帮助消息找到对象,
    * 找到对象以后,帮助小明操持婚礼,带消息
    * */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //帮他找到对象
        before();

        //这个invoke就会掉到被代理类中的method
        method.invoke(people,args);

        after();

        return null;
    }

    /*
    *  这个方法是小明在找到对象之前,父母帮助他做得事情
    * */
    private void before() {
        System.out.println("我是小明的父母,我需要帮助小明找对象!!");
    }

    /*
    * 找到对象之前,父母帮助他操持婚礼,带小孩
    * */
    private void after() {
        System.out.println("我是小明的父母,我们需要帮助小明操持婚礼,帮他带小孩");
    }
}
package com.zhuguang.jack.proxy;

import sun.misc.ProxyGenerator;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        //proxy对象就是xiaoming这个对象的一个代理实例,xiaoming这个对象就是一个被代理
        People proxy = (People)Proxy.newProxyInstance(People.class.getClassLoader(),new Class[]{People.class},
                new Parent(new Xiaoming()));
        proxy.zhaoduixiang();

        proxy.yanghaizi();

        createProxyClassFile();
    }

    public static void createProxyClassFile() {
        byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});

        try {
            FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class");
            fileOutputStream.write($Proxy0s);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

通过以上几段代码,我们就实现了JDK的动态代理的技术了。我们的核心方法就是Xiaoming这个类实现了zhaoduixiang这件事。但是,通过动态代理,我们对小明找对象这件事情实现了功能的增强。找对象之前和找对象之后。

那么,它是如何实现这样的增强的呢?

我们可以在根目录下找到代理类$proxy的class文件了:

Spring之AOP技术 (6)_第1张图片

下面贴出来代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.zhuguang.jack.proxy.People;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements People {
    private static Method m1;
    private static Method m4;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void yanghaizi() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void zhaoduixiang() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.zhuguang.jack.proxy.People").getMethod("yanghaizi");
            m3 = Class.forName("com.zhuguang.jack.proxy.People").getMethod("zhaoduixiang");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

通过代理类 $Proxy0我们知道,这个代理类实现了接口People。也就是说,我们时间调用的是内存中的代理类的  $Proxy0.zhaoduixiang() 方法。 而这个方法内部, 通过反射又调用了 h.invoke(this, m3, (Object[])null), 那这个h是什么呢? 其实,它就是parent的实例。m3 是什么呢?m3对应的就是zhaoduixiang()这个方法。

调用逻辑就是:$Proxy0.zhaoduixiang()   --- > h.invoke(this, m3, (Object[])null)   h是parent实例 ---->  xiaoming.zhaoduixiang().  因为,我们在parent的invoke方法中实现了对zhaoduixiang()的增强。也就是在找对象之前,之后,我们还可以添加好多方法去干别的事情。这样也就实现了增强功能。

2. cglib动态代理:

我们首先需要引入依赖包:


      cglib
      cglib
      3.2.5
    
    
      cglib
      cglib-nodep
      3.2.5
    

被代理类:

package com.zhuguang.jack.cglib;

/*
* 这里不实现接口
* */
public class TargetClass {

    public void add() {
        System.out.println("TargetClass.add");
    }

    /*
    * 这里有一个开启事务
    * */
    public void del() {
        System.out.println("TargetClass.del");
    }


    /*
    * 增强缓存
    * */
    public void query() {
        System.out.println("TargetClass.query");
    }

}

针对被代理类3个方法的3个增强:

package com.zhuguang.jack.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;



//这个是对add方法的一个拦截
public class AddInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("AddInterceptor.intercept.before");
//        method.invoke(obj,args);
        proxy.invokeSuper(obj,args);
        System.out.println("AddInterceptor.intercept.after");
        return null;
    }
}
package com.zhuguang.jack.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class DelInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("DelInterceptor.intercept.before");
        proxy.invokeSuper(obj,args);
        System.out.println("DelInterceptor.intercept.after");
        return null;
    }
}
package com.zhuguang.jack.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class QueryInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("QueryInterceptor.intercept.before");
        proxy.invokeSuper(obj,args);
        System.out.println("QueryInterceptor.intercept.after");
        return null;
    }
}

工厂:

package com.zhuguang.jack.cglib;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;

public class CglibInstanceFactory {

    public static Object getInstance() {

        //拿到字节码增强器
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TargetClass.class);
        enhancer.setCallbackFilter(new CglibFilter());

        Callback[] callbacks = {
                new AddInterceptor(),
                new DelInterceptor(),
                new QueryInterceptor()};
        enhancer.setCallbacks(callbacks);
        return enhancer.create();
    }
}

测试类:

package com.zhuguang.jack.cglib;

public class Test {
    public static void main(String[] args) {
        TargetClass instance = (TargetClass)CglibInstanceFactory.getInstance();
        instance.query();
    }
}

这就是cglib的动态代理。

3、Spring AOP 动态代理类生成

 上一讲,我们已经说到了AOP的开启,其实就是AnnotationAwareAspectJAutoProxyCreator注入并实例化BeanDefinition。

我们在Spring之实例化Bean _ @Resource和@Autowired实现原理(3)_chen_yao_kerr的博客-CSDN博客

中重点谈到了populateBean() 和 initializeBean()这两个方法。而我说initializeBean() 方法是对Bean进行初始化操作的。其实这个方法也是AOP的入口方法:

Spring之AOP技术 (6)_第2张图片

 进入这个方法:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//调用Aware方法
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//对类中某些特殊方法的调用,比如@PostConstruct,Aware接口,非常重要 重要程度 :5
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//InitializingBean接口,afterPropertiesSet,init-method属性调用,非常重要,重要程度:5
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//这个地方可能生出代理实例,是aop的入口
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	} 
  

 里面备注已经说明applyBeanPostProcessorsAfterInitialization就是AOP的入口,具体就是调用postProcessor接口进行支持的。而我们今天需要关注的则是AnnotationAwareAspectJAutoProxyCreator.

首先,定义好切面类:

package com.xiangxue.jack.aop.aspectj;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectAnnotation {

    @Pointcut("execution(public * com.xiangxue.jack.service.*.queryUser(..))")
    public void pc1(){}

    @Before("pc1()")
    public void before() throws Throwable {
        System.out.println("==============before =========");
    }
    @Around("pc1()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("============== before 111=========");
        Object result = joinPoint.proceed();
        System.out.println("==============after 111 =========");

        return result;
    }
    @After("pc1()")
    public void after() throws Throwable {
        System.out.println("==============After=========");
    }
    @AfterReturning("pc1()")
    public void afterReturn() throws Throwable {
        System.out.println("==============afterReturn =========");
    }
    @AfterThrowing("pc1()")
    public void afterThrowing() throws Throwable {
        System.out.println("==============afterThrowing =========");
    }
   /* @Before("pc2()")
    public void before() {
        System.out.println("===============只拦截add方法=========");
    }

    @Before("pc3()")
    public void before1(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        Object[] args = joinPoint.getArgs();
        System.out.println("===============service1包的拦截=========");
    }

    @Before("pc3()&&args(bankId,id,list)")
    public void before2(String bankId,Integer id,List list) {
        System.out.println("===============service1包的拦截=========");
    }

    @Before(value = "@annotation(targetMethod)",argNames = "joinPoint,targetMethod")
    public void xx(JoinPoint joinPoint, TargetMethod targetMethod) {
        System.out.println("===============注解拦截 前置通知=========");
        System.out.println("==================targetMethod.name = " + targetMethod.name());
    }

    @AfterReturning(value = "@annotation(returnValue)",returning = "retVal")
    public void afterReturning(JoinPoint joinPoint, ReturnValue returnValue, Object retVal) {
        System.out.println("==============AspectAnnotation 后置通知  拿返回值=========" + retVal);
    }

    @AfterThrowing(value = "@annotation(throwsAnno)",throwing = "e")
    public void throwMethod(JoinPoint joinPoint, ThrowsAnno throwsAnno, Throwable e) {
        System.out.println("==============AspectAnnotation 异常通知  拿异常=========" + e);
    }*/
}

需要被拦截的类:

package com.xiangxue.jack.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Lazy
@Primary
@Service
public class UserServiceImpl1 implements UserService {

    @Autowired
    AccountService accountService;

    @Override
    public String queryUser(String userId) {
        System.out.println("UserServiceImpl1 ->" + userId);
        return "UserServiceImpl1 ->" + userId;
    }

    @Override
    public void addxx(String id) {
        System.out.println("UserServiceImpl1 -> addxx :" + id);
    }
}

ok,准备工作搞定,还是接着我们的源码bebug;

首先,我们的Spring会实例化Bean,然后判断这个实例化后的bean对象是否需要进行代理类的生成:

Spring之AOP技术 (6)_第3张图片

 Spring之AOP技术 (6)_第4张图片

其实,就是找到所有的切面类,也就是有@Aspect注解的类。然后,根据当前的beanName找到能够拦截当前bean的切面。如果能找到,则为当前bean生成代理类proxy;如果找不到,则不生成;

Spring之AOP技术 (6)_第5张图片

 4. 找切面的具体过程

@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class beanClass, String beanName, @Nullable TargetSource targetSource) {

		//找到合格的切面,重点看
		List advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

Spring之AOP技术 (6)_第6张图片

4. 1 找所有切面 

Spring之AOP技术 (6)_第7张图片

重点关注一下这个 buildAspectJAdvisors()方法:

Spring之AOP技术 (6)_第8张图片

它是如何拿到所有BeanDefinition的呢?其实,我们在实例化BeanDefinition的时候,是放入缓存中的。一个是beanDefinitionName,还有一个是beanDefinitionMap. 这里我们就用到了这2个缓存:

Spring之AOP技术 (6)_第9张图片

第二个问题,它是如何创建切面的呢?

其实,就是找到有@Aspect注解的class对象,然后找到该对象中所有的method方法,只要不是含有@PointCut注解的方法,就进行搜集;如下图:

Spring之AOP技术 (6)_第10张图片

Spring之AOP技术 (6)_第11张图片 

获取到所有的method方法以后,对把method方法和pointCut方法进行包装,封装成Advisor

Spring之AOP技术 (6)_第12张图片

Spring之AOP技术 (6)_第13张图片 

 

 

需要细说一下:

1. 我们找到了有注解@Aspect的class文件了,说明这是一个切面;

2. 然后,我们会找到里面所有有注解的方法,除了@PonitCut注解。

3. 此时,我们会搜集@Before,@Around, @After @AfterReturnning @ AfterThrowing等注解。 并且把这些注解、注解里面的信息,比如表达式、参数、注解类型等封装成AspectJAnnotation。 然后创建PointCut对象,把注解对象中的表达式设置到pointCut对象中,最后创建Advice对象。

4. 此处,不同的注解会生成不同的Advice对象。比如:AspectJAroundAdvice、AspectJMethodBeforeAdvice、AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice、AspectJAfterAdcvice。

5. 因为,Advice本身就是最小单位的切面,因此,最终会把Advice和pointCut封装成切面Advisor对象。

4.2 找到合格的切面 

上一步,我们已经拿到了所有的切面对象了。接下来,我们就是要根据匹配规则,去找到对象的切面对象了。其实,就是根据pointCut对象中的表达式进行匹配。如果表达式中包含了当前的bean,那这就是一个合格的切面,当前的bean就需要生成代理对象

Spring之AOP技术 (6)_第14张图片

 4.3 对切面进行排序

排序很重要,这涉及到切面的链式调用,后面说。此处,我们需要知道,拿到的所有切面是经过排序的。 

Spring之AOP技术 (6)_第15张图片

5. 生成代理对象

Spring之AOP技术 (6)_第16张图片

 具体步骤如下:

protected Object createProxy(Class beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		//创建代理工厂
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				//proxyTargetClass 是否对类进行代理,而不是对接口进行代理,设置为true时,使用CGLib代理。
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		//把advice类型的增强包装成advisor切面
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		用来控制代理工厂被配置后,是否还允许修改代理的配置,默认为false
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		//获取代理实例
		return proxyFactory.getProxy(getProxyClassLoader());
	}

1、 创建代理工厂对象proxyFactory

2.  切面对象重新包装,会把自定义的MethodInterceptor 类型的类包装成advisor切面并放入到代理工厂中去

3. 根据 proxyTargetClass 配置生成JDK动态代理还是cglib动态代理

4.创建代理对象,并把代理对象传递到jdk和cglib中

Spring之AOP技术 (6)_第17张图片

Spring之AOP技术 (6)_第18张图片

6、 代理类的调用:此处以jdk代理类为例

cglib的调用和jdk代理类的调用逻辑一样。动态代理的链式调用,其实就是一个变种的职责链模式,可以简单连接一下相关设计模式:【行为型模式】《大话设计模式》——读后感 (16)加薪非要老板批?——职责链模式_chen_yao_kerr的博客-CSDN博客

测试类:

package com.xiangxue.jack.test;

import com.xiangxue.jack.AOP.ComponentScanBean;
import com.xiangxue.jack.service.UserService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AopTest {

    @Autowired
    UserService userService;

    private ApplicationContext applicationContext;

  /*  @Before
    public void before() {
        applicationContext = new AnnotationConfigApplicationContext(ComponentScanBean.class);
    }*/

    @Test
    public void test1() {
        applicationContext = new AnnotationConfigApplicationContext(ComponentScanBean.class);
        UserService userService = applicationContext.getBean(UserService.class);
        userService.queryUser("jack");

        userService.addxx("1");
    }

    /*  @Test
    public void circularRef() {
        UserService userService = applicationContext.getBean(UserService.class);
        AccountService accountService = applicationContext.getBean(AccountService.class);
        userService.queryUser("1");
        accountService.queryAccount("2");
    }

    @Test
    public void test2() {
        BankService bankService = applicationContext.getBean(BankService.class);
        System.out.println(bankService.queryBank("jack",1,new ArrayList()));
    }

    @Test
    public void introductionTest() {
        BankService bean = applicationContext.getBean(BankService.class);
        System.out.println(bean.queryBank("jack",1,new ArrayList()));

        DataCheck dataCheck = (DataCheck)bean;
        dataCheck.check();
    }*/

    /*
    * 可以做一波甜点,带着找问题
    * */
   /* @Test
    public void costomInterceptorTest() {

        AnnotationAwareAspectJAutoProxyCreator bean = applicationContext.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        bean.setInterceptorNames("girlMethodInterceptor");

        UserService userService = applicationContext.getBean(UserService.class);
        userService.queryUser("a");
    }
*/
   /* @Test
    public void proxyFactoryTest() {
        ProxyFactory pf = new ProxyFactory();
        pf.setTarget(new UserServiceImpl());
        pf.addAdvice(new BeforeAdviceBean());

        UserServiceImpl proxy = (UserServiceImpl)pf.getProxy();
    }

    @Test
    public void annoIntercepoter() {
        BankService bean = applicationContext.getBean(BankService.class);
        bean.queryArea("jack");
        bean.returnValue("jack");
        bean.ThrowMethod("jack");
    }*/
}

在我们调用到 userService.queryUser("jack"); 的时候,我们会进入到JdkDynamicAopProxy类的invoke方法中,因为这个类实现了 InvocationHandler 接口:

Spring之AOP技术 (6)_第19张图片

核心步骤:

1. 首先,我们会从代理工厂中拿过滤器链。 Object是一个MethodInterceptor类型的对象,其实就是对advice对象包装了的新对象。其实,就是拿到所有带有注解的的拦截方法,但是他们也是最小的切面。这是我们在生成代理对象的时候传进去的

Spring之AOP技术 (6)_第20张图片

2. 拿不到调用链的话,说明没有拦截的方法。我们直接调用核心方法,也就是我们的业务方法。如果能够拿到,上面我们说过对切面进行排序操作的,此时我们会根据排好序的Advisor进行调用。说白了,就是有顺序的调用。不管调用顺序如何,最终代码肯定是按照 Around (before 核心业务方法   after) --- > afterReturning --> afterThrowing 这种顺序进行逻辑处理。

3. invocation.proceed() 这个方法就是进入链式调用的意思。也就是说,不管是afterThrowing、afterReturning、after、Around、before 他们都会调用proceed()方法进入链式调用,否则的话,有些方法就会不起作用。

举个例:@Around注解包含了3个步骤。 即业务代码之前  业务代码  业务代码之后。 如果我们不在自己写的Around方法内部调用proceed()方法,那么我们的@Around方法就会缺失部分调用,有可能调用了业务代码之前,然后就停止拦截了,导致业务代码都无法走完。

再举个例子。我们既有@Before拦截,也有@Around拦截,还有@After拦截,当然这样的拦截是不合理的,因为@Around拦截有包含了@Before和@After。此次,就是为了举个例子。如果@Around方法体内部不调用proceed()方法,那么@After方法就不会被调用,也就导致链式调用无法完成。

链式调用的核心方法:

@Override
	@Nullable
	public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		//如果执行链中的advice全部执行完,则直接调用joinPoint方法,就是被代理方法
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.

			//调用MethodInterceptor中的invoke方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

调用顺序:

 AspectJAfterReturningAdvice

AspectJAfterThrowingAdvice

AspectJAfterAdvice AspectJAroundAdvice MethodBeforeAdviceInterceptor
拦截方法 proceed 拦截方法 proceed 拦截方法 proceed 拦截方法 proceed
1. 直接进入下一次链式调用
2. 直接进入下一次链式调用
3、进入拦截方法执行 4、执行完以后,需要自己手动调用proceeed方法进行下一次链式调用
5,@Before需要在业务方法之前调用,所有会直接进入拦截方法 6、执行完以后会调用proceed进入下一次链式调用
7、在proceed方法中,我们会调用invokeJoinpoint()。此时,我们会进入到我们的核心业务方法调用。最后退回到链式调用的大流程中去
8. 此时,退回到proceed()方法,执行剩余方法
9. 此时,我们会进入到@After的拦截方法中,执行代码
10、最后退回到@AfterReturning的方法体中,执行方法
11. 最终,完成所有拦截方法的调用,也就是Advice方法的链式调用

下面看一下,每个Advice是如何实现链式调用的。

首先调用AspectJAfterThrowingAdvice,直接进入下一次链式调用(不会进入拦截方法)

Spring之AOP技术 (6)_第21张图片

AfterReturningAdviceInterceptor 直接进入下一次链式调用(不会进入拦截方法)

Spring之AOP技术 (6)_第22张图片

 AspectJAfterAdvice 直接进入下一次链式调用(不会进入拦截方法)

Spring之AOP技术 (6)_第23张图片

AspectJAroundAdvice 内部没有链式调用,所有直接进入拦截方法中。在拦截方法中,我们需要自己手动调用proceed方法进行链式调用

Spring之AOP技术 (6)_第24张图片

 在拦截方法中,我们可以调用一些没有注解的增强方法,然后再次进入调用链Spring之AOP技术 (6)_第25张图片

MethodBeforeAdviceInterceptor @Before是需要在业务方法之前调用的,所有会进入拦截方法,执行完以后,会自动调用proceed进入调用链,执行我们的核心业务方法。

Spring之AOP技术 (6)_第26张图片

 在调用完@Before以后,我们会调用核心业务方法Spring之AOP技术 (6)_第27张图片

最后,我们看一下打印结果信息,验证一下我们的代码调用流程分析系是否准确

Spring之AOP技术 (6)_第28张图片

你可能感兴趣的:(Spring源码,spring,java,代理模式)