Aop源码解读,解密Aop

1.AOP是什么

网络上很多解释,本文不在赘述,大致意思就好比,比如你一个月前开发了一个代码,功能就是一个除法功能,而现在,你想在原有除法功能基础上,记录传入的参数(除数,被除数)到数据库,并且在除法功能完成后,记录一下返回值到数据库。按照以前的逻辑是需要到这个除法功能里面,修改原有代码。当然,这个除法功能相对比较简单,修改原有代码不复杂,但是实际生产上的业务肯定是比这个复杂的多,改代码的风险也是不可预计的。在设计模式有一种原则就是开闭原则,对修改关闭,对扩展开放,也是为了规避这一风险,所以spring的Aop很好的做到了这一点。

2.如何使用AOP

引入spring和springAop还有junit的相关jar包

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>SpringDemo</groupId>
	<artifactId>SpringDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.0.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>5.0.4.RELEASE</version>
		</dependency>
	</dependencies>
</project>

 定义配置类

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.erwan.cap12.Bean")
public class Cap12MainConfigAop {
	@Bean
	public Calculator calculator() {
		return new Calculator();
	}

	@Bean
	public CalculatorAop calculatorAop() {
		return new CalculatorAop();
	}
}

其中EnableAspectJAutoProxy注解就是开启AOP功能

//原有代码,提供除法功能的类


public class Calculator {
	public int div(final int i, final int j) {
		System.out.println("--------");
		return i / j;
	}

}

定义一个切面类,来扩展Calculator

@Aspect
public class CalculatorAop {

	@Around("pointCut()")
	public Object AroundCalculator(final ProceedingJoinPoint proceedingJoinPoint)
 throws Throwable {
		System.out.println("@Around:执行目标方法之前...");
		Object obj = proceedingJoinPoint.proceed();// 相当于开始执行div
		System.out.println("@Arountd:执行目标方法之后...");
		return obj;
	}

	@Before("pointCut()")
	public void logBefore(final JoinPoint joinPoint) {
		System.out.println("div开始前" + Arrays.asList(joinPoint.getArgs()));
	}

	@After("pointCut()")
	public void logEnd(final JoinPoint joinPoint) {
		System.out.println("div开始后" + Arrays.asList(joinPoint.getArgs()));
	}

	@AfterThrowing(value = "pointCut()", throwing = "ex")
	public void logException(final Exception ex) {
		System.out.println("div发生异常" + ex.getMessage());
	}

	@AfterReturning(value = "pointCut()", returning = "result")
	public void logReturn(final Object result) {
		System.out.println("div返回值" + result);
	}

	@Pointcut("execution(public * com.erwan.cap12.Bean.Calculator.*(..))")
	public void pointCut() {

	}
}

测试类:

@Test
public void cap12() {
  AnnotationConfigApplicationContext context = new 
  AnnotationConfigApplicationContext(Cap12MainConfigAop.class);
  Calculator bean = context.getBean(Calculator.class);
  bean.div(4, 2);
}

测试结果如下:
@Around:执行目标方法之前...
div开始前[4, 2]
Calculator自己运行的div
@Arountd:执行目标方法之后...
div开始后[4, 2]
div返回值2
		

所以使用aop就以下三步

1,将业务逻辑组件和切面类都加入到容器中, 告诉spring哪个是切面类(@Aspect)

  2,在切面类上的每个通知方法上标注通知注解, 告诉Spring何时运行(写好切入点表达式,参照官方文档)

  3,开启基于注解的AOP模式  @EnableAspectJAutoProxy

 

SpringAOP可以应用5种类型的通知:

1.前置通知(Before):在目标方法被调用之前调用通知功能。

2.后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。

3.返回通知(After-returning):在目标方法成功执行之后调用通知。

4.异常通知(After-throwing):在目标方法抛出异常后调用通知。

5.环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
其中环绕通知比较特殊,他可以在注解的方法体(AroundCalculator)定义是否执行目标方法,如果不执行,则After 和After-returning则不生效,他也可以在捕捉到异常后,重新执行目标方法(div),功能比较强大

其中@Pointcut就是定义需要拦截或者说增强的目标类和目标类的方法,其中 Calculator.*(..)代表 Calculator类的所有方法就是增强所有方法的调用。

使用JoinPoint可以拿到相关的内容, 比如方法名,  参数

 

aop源码解读

在aop的使用中我们提到,如何使用Aop

  1,将业务逻辑组件和切面类都加入到容器中, 告诉spring哪个是切面类(@Aspect)

  2,在切面类上的每个通知方法上标注通知注解, 告诉Spring何时运行(写好切入点表达式,参照官方文档)

  3,开启基于注解的AOP模式  @EnableAspectJAutoProxy

这里我们需要从配置类的注解@EnableAspectJAutoProxy入手,打开这个注解显示如下:

//导入了此类,点进去看
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   //proxyTargetClass属性,默认false,采用JDK动态代理织入增强(实现接口的方式);如果设为true,则采 
    用CGLIB动态代理织入增强
 	boolean proxyTargetClass() default false;
    //通过aop框架暴露该代理对象,aopContext能够访问
 	boolean exposeProxy() default false;
}

这个注解里面 包括两点,@Import注解和  proxyTargetClass参数

 其中proxyTargetClass默认为false,就用cglib来代理增强,如果为true则通过jdk来动态代理增强

   cglib和jdk的动态代理这里可以参考我的另外一篇文章解密动态代理,cglib和jdk动态代理

   @Import功能也可以参考二万的另外一篇文章深入理解 @Import注解

@Import就是可以在容器中注入bean,也可以实现ImportBeanDefinitionRegistrar接口,通过实现ImportBeanDefinitionRegistrar接口来拿到BeanDefinitionRegistry,然后通过 BeanDefinitionRegistry 向ioc容器中注册bean。

 通过@Import看到,引入了AspectJAutoProxyRegistrar

接下来我们来看看AspectJAutoProxyRegistrar这个类,它实现了ImportBeanDefinitionRegistrar。

实现这个接口ImportBeanDefinitionRegistrar可以在它原有的方法registerBeanDefinitions中得到 BeanDefinitionRegistry registry, 这个registry可以把具体的bean注入到容器中。

/*
*实现了ImportBeanDefinitionRegistrar这个接口,并且可以通过重写其registerBeanDefinitions方法
*拿到BeanDefinitionRegistry registry  ,然后通过registry向ioc容器中注册bean。
*
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //这行代码的功能就是,通过registry向ioc容器中注入AnnotationAwareAspectJAutoProxyCreator 这个bean
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

接下来我们看    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这行代码持续跟进,进入AopConfigUtils类,最后走到BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
            @Nullable Object source) ,实现向ioc容器注入bean。(实现原理可以看上面的@Import功能)

 

@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
			@Nullable Object source) {

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
        //先定义RootBeanDefinition,然后注册bean。
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
       //注册了一个bean名称为AUTO_PROXY_CREATOR_BEAN_NAME,
        //类为 AnnotationAwareAspectJAutoProxyCreator的bean
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

 

AUTO_PROXY_CREATOR_BEAN_NAME 是常量,值为:org.springframework.aop.config.internalAutoProxyCreator

所以总的来说就是注册了一个bean名称为org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator.class

接下来 我们看 AnnotationAwareAspectJAutoProxyCreator这个类

è¿éåå¾çæè¿°

它的顶层就是BeanPostProcessor,beanPostProcessor就是bean的后置处理器,通俗来说就是在一个普通bean(Calculator)创建后,为这个Calculator做一些其他事,比如说通过动态代理来增强这个bCalculatoran。可以参考解密动态代理,cglib和jdk动态代理

在阅读源码后,发现在bean的生命周期中,是先创建Calculator,然后赋值,然后初始化Calculator,也就是在初始化Calculator的时候通过动态代理对beanCalculator增强。

bean的生命周期可以得到如下内容:

ioc容器通过构造函数创建Calculator

    populateBean(beanName, mbd, instanceWrapper); 对Calculator属性赋值,如果有

     exposedObject = initializeBean(beanName, exposedObject, mbd);  初始化Calculator

initializeBean 的内部包括以下3点

1.invokeAwareMethods()对实现了 aware的接口,调用对应的方法得到对应的bean,比如实现beanFactoryAware可以得到beanFactory,具体可以参考Spring Aware接口的奇妙用处

2.applyBeanPostProcessorsBeforeInitialization

3.nvokeInitMethods 在构造器后调用的方法 InitializingBean. afterPropertiesSet 之后invokeCustomInitMethod 调用初始化方法

4.执行AbstractAutoProxyCreator.postProcessBeforeInstantiation //这里实现动态代理创建对象

bean的生命周期是通过阅读源码得到的,以上只是总结,具体可以参考spring bean的生命周期

下面我们来研究bean在初始化的时候,如何调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation这个内容,又是如何实现动态代理对象的创建的。

在初始化Calculate的时候是如何调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation 这个呢,下面截取部分源码

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}

通过前面我们对@EnableAspectJAutoProxy开启aop功能的注解时候,得到通过@Import向 ioc容器中注入了AnnotationAwareAspectJAutoProxyCreator这个类,并且这个类实现了BeanPostPRocessor,所以是所以这个类可以在容器中通过getBeanPostProcessors得到的。

通过多态的原理我们可以知道调用BeanPostProcessor.postProcessBeforeInitialization可以调用到具体实现类的方法。

而AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator,所以最后调用到的是

AbstractAutoProxyCreator.postProcessBeforeInstantiation

我们接下来看看AbstractAutoProxyCreator.postProcessBeforeInstantiation到底做了什么

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	Object cacheKey = getCacheKey(beanClass, beanName);

	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}

	// Create proxy here if we have a custom TargetSource.
	// Suppresses unnecessary default instantiation of the target bean:
	// The TargetSource will handle target instances in a custom fashion.
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		if (StringUtils.hasLength(beanName)) {
			this.targetSourcedBeans.add(beanName);
		}
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
		Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	return null;
}

这里可以看到,这个方法做了两个内容,

一是得到所有的通知advices,也就是得到CalculatorAop 中  @AfterThrowing,@AfterReturing,@before @@Around这些注解的具体内容

二就是创建动态代理对象

动态代理对象得到了,之后就是通过拦截方法,来实现aop功能。

Calculator bean = context.getBean(Calculator.class); 得到动态代理对象

调用CalCulator的div的时候,动态代理会对具体方法进行拦截,然后执行自己的特定内容。也就是调用这一行代码:  bean.div(4, 2);

因为我们这里使用的Caculator类来做的aop,所以动态代理使用的cglib,接口用的是jdk动态代理

通过cglib我们可以得到在cglib的callback函数中来实现对方法div的拦截

继续研究AbstractAutoProxyCreator.postProcessBeforeInstantiation 中如何创建cglib动态代理对象(也就是cglib的增强对象)的

研究AbstractAutoProxyCreator.postProcessBeforeInstantiation方法中的 这一行   Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);

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)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}
    //得到通知advices的所有内容
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}
    //创建具体动态代理对象
	return proxyFactory.getProxy(getProxyClassLoader());
}

我们接着看return proxyFactory.getProxy(getProxyClassLoader());这一行的具体内容

public Object getProxy(@Nullable ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }

跟进createAopProxy()

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}

最后跟踪到DefaultAopProxyFactory的    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException 这个方法


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
        //是否是接口或者proxyClass为true
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

可以看到如果@EnableAspectJAutoProxy注解proxyTargetClass的属性是true或者增强对象(Calculator)是接口的话,就创建jdk动态代理。

通过我们前面看到我们@EnableAspectJAutoProxy并没有指定proxyTargetClass为true(通过查看@EanbleAspectJAutoProxy得到,默认为false):boolean proxyTargetClass() default false;

Calculator也不是接口,所以这里创建的是ObjenesisCglibAopProxy动态代理对象

我们来查看class ObjenesisCglibAopProxy extends CglibAopProxy 这个类,可以发现它是 继承CglibAopProxy。

而CglibAopProxy则是整个Calculator方法拦截的核心。

通过解密动态代理,cglib和jdk动态代理这里得到

分析cglib动态代理执行拦截的方法是当Calculator.div调用的时候,会通过设置的callBack函数(并且这个函数实现了MethodInterceptor这个接口),执行这个CallBack函数的intercept方法。

所以研究CglibAopProxy这个类最核心的地方是找到这个callBack函数和intercept方法,在二万多次调试中得到

Calculator的div方法是被CglibAopProxy的内部类DynamicAdvisedInterceptor进行拦截的

所以我们这里研究DynamicAdvisedInterceptor 的    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable方法(这里你们可以直接在这个方法内部打个断点论证一下)

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	TargetSource targetSource = this.advised.getTargetSource();
	try {
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		// Check whether we only have one InvokerInterceptor: that is,
		// no real advice, but just reflective invocation of the target.
		if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
			// We can skip creating a MethodInvocation: just invoke the target directly.
			// Note that the final invoker must be an InvokerInterceptor, so we know
			// it does nothing but a reflective operation on the target, and no hot
			// swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = methodProxy.invoke(target, argsToUse);
		}
		else {
			// We need to create a method invocation...
			retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

通过调试得到拦截链这个list<Object>chain中的存放顺序是

before这个通知应该是第一个执行的,为什么会是放在最后,我们接下来分析。

这个方法中,先是得到拦截链,然后通过拦截链来依次执行,达到对aop的五种类型的通知逆序序执行。如果拦截链为空,则直接通过    retVal = methodProxy.invoke(target, argsToUse);执行Calculator.div方法

这里拦截链有一个很有意思的点是,他通过多态+递归的方法,来达到先进后出,逆序执行的目的的。

就是    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 这行代码达到AOp通知的具体通知的。

我们来看看CglibMethodInvocation.proceed这个方法

public Object proceed() throws Throwable {
	//	We start with an index of -1 and increment early.
	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;
		if (dm.methodMatcher.matches(this.method, this.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.
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

执行逻辑如下:

1.    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }//判断 currentInterceptorIndex是否等于拦截链的长度6,这里currentInterceptorIndex初始值为-1,不等于,所以往下走

2.Object interceptorOrInterceptionAdvice=this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)获得具体拦截链的执行方法,interceptorsAndDynamicMethodMatchers这个map中获得index为0的拦截链执行方法ExposeInvocationInterceptor

3.((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)执行,ExposeInvocationInterceptor.invoke的方法

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	MethodInvocation oldInvocation = invocation.get();
	invocation.set(mi);
	try {
		return mi.proceed();
	}
	finally {
		invocation.set(oldInvocation);
	}
}

在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法

4.继续获得具体的拦截链执行方法,获得index为1的拦截链执行方法AspectJAfterThrowingAdvice

5.执行AspectJAfterThrowingAdvice.invoke()方法

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	catch (Throwable ex) {
		if (shouldInvokeOnThrowing(ex)) {
			invokeAdviceMethod(getJoinPointMatch(), null, ex);
		}
		throw ex;
	}
}

6.在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于2的拦截链执行方法AfterReturningAdviceInterceptor

7.执行AfterReturningAdviceInterceptor.invoke()

public Object invoke(MethodInvocation mi) throws Throwable {
	Object retVal = mi.proceed();
	this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
	return retVal;
}

8.在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于3的拦截链执行方法AspectJAfterAdvice

9.执行AspectJAfterAdvice.invoke方法

public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	finally {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
}

10.执行mi.proceed方法,又调用到CglibMethodInvocation.proceed()这个方法,获得index等于4的拦截链执行方法AspectJAroundAdvice,执行AspectJAroundAdvice.invoke()方法

11..在mi.proceed()方法又调用到CglibMethodInvocation.proceed()这个方法,获得index等于5的拦截链执行方法MethodBeforeAdviceInterceptor,执行MethodBeforeAdviceInterceptor.invoke()

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
	return mi.proceed();
}

从这里看到先执行的通知方法 @Before 打印出div开始前[4, 2],然后执行的mi.proceed();又调用到

CglibMethodInvocation.proceed(),然后his.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1这个判断条件成立,进入invokeJoinpoint方法,调用到CglibAopProxy的invokeJoinpoint方法

protected Object invokeJoinpoint() throws Throwable {
	if (this.publicMethod) {
		return this.methodProxy.invoke(this.target, this.arguments);
	}
	else {
		return super.invokeJoinpoint();
	}
}

这个方法就最后就是调用java.refelt.Method.invoke,来达到执行Calculate.div方法,并且打印,Calculator自己运行的div,这句话。

然后开始递归的回溯,依次进行AspectJAfterAdvice,AfterReturningAdviceInterceptor,AspectJAfterThrowingAdvice,ExposeInvocationInterceptor的剩余逻辑,依次打出div开始后[4, 2],div返回值2 这些话

 

Aop流程如下:

1.向ioc容器注册一个bean名称为org.springframework.aop.config.internalAutoProxyCreator,类为AnnotationAwareAspectJAutoProxyCreator.class

 2.通过实现BeanPostProcessor接口,成为BeanPostProcessor。在Calculate这个bean创建后的初始化逻辑中,通过for循环遍历所有BeanPostProcessor,调用BeanPostProcessor.postProcessBeforeInstantiation来调用到AbstractAutoProxyCreator.postProcessBeforeInstantiation这个方法,得到所有的通知,并且创建cglib动态代理对象,并且在cglib中设置的callback函数为DynamicAdvisedInterceptor,如果执行Caculator的方法,就会进入到DynamicAdvisedInterceptor拦截方法中,DynamicAdvisedInterceptor为CglibAopProxy的内部类

此时ioc容器中的Calculator这个对象就是一个增强后的对象

3.通过ioc容器得到增强后的对象   Calculator bean = context.getBean(Calculator.class);

 4.调用bean.div(4, 2); 方法,被CglibAopProxy中的public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable所拦截。

5.执行retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();进入到

ReflectiveMethodInvocation.proceed()方法。利用多态和递归,逆序的实现拦截链的调用。

这里提一下,这里的多态就是,一个接口有多个实现,而调用直接用接口调用方法,在运行时jvm会根据具体接口的实例来调用具体的逻辑。
        

 

ioc容器先对Calculator进行增强,在beanCalculator增强后,将这个bean(Calculator)注入到ioc容器中,简单的说也就是放在ioc的一个总的Map中

在从ioc容器中获得Calculator的时候,就得到了增强后的Calculator。也就是调用这一行代码:   Calculator bean = context.getBean(Calculator.class);

调用CalCulator的div的时候,动态代理会对具体方法进行拦截,然后执行自己的特定内容。也就是调用这一行代码:  bean.div(4, 2);

 

所以在Calculator在容器初始化的时候,具体逻辑如下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值