SpringFramework源码分析(5):AOP的使用与实现

本篇文章介绍下SpringAOP的用法以及源码分析。

1 SpringAOP使用示例

我们定义四个类

  • MathCalculator是业务类,我们希望在divide方法运行前后、正常返回或者抛异常时,打印一些日志。
  • LogAspect是切面类,我们在LogAspect上标注了@Aspect注解,表示这是一个切面。在类中,我们使用@Pointcut定义了一个切点,使用@Before定义了前置通知、@After定义了后置通知、@AfterReturning定义了返回通知、@AfterThrowing定义了异常通知、@Around定义了环绕通知
  • MainConfigOfAop是配置类。注意我们在MainConfigOfAop上加入了注解@EnableAspectJAutoProxy,也就是声明了我们要开启AspectJ自动代理功能。
  • IocAopTest是测试类。运行测试类返回的结果如下。
    logAround, before method:[divide] execute
    logStart, parameterNameWithValue:[MethodName:divide Parameters: x:2 y:1 ]
    logEnd
    logReturn, method:[divide], result:[2]
package com.woods.aop;

/**
 * 业务类,一个数学计算器
 */
public class MathCalculator {

    public int divide(int x, int y) {
        return x / y;
    }
}

package com.woods.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

/**
 * 切面
 */
@Aspect
public class LogAspect {

    /**
     * 抽取公共的切点表达式
     */
    @Pointcut("execution(public int com.woods.aop.MathCalculator.*(..))")
    public void pointCut() {
    }

    /**
     * public int com.woods.aop.MathCalculator.div(int, int)是切入点表达式,指定在哪个方法进行切入
     * public int com.woods.aop.MathCalculator.*(..)表示MathCalculator的任意参数的任意方法的
     */
    //    @Before("public int com.woods.aop.MathCalculator.div(int, int)")
    @Before("com.woods.aop.LogAspect.pointCut()")
    public void logStart(JoinPoint joinPoint) {
        String parameterNameWithValue = getParameterNameWithValue(joinPoint);
        System.out.printf("logStart, parameterNameWithValue:[%s]\n", parameterNameWithValue);
    }

    @After("pointCut()")
    public void logEnd() {
        System.out.println("logEnd");
    }

    @AfterReturning(value = "pointCut()", returning = "result")
    public void logReturn(JoinPoint joinPoint, Object result) {
        System.out.printf("logReturn, method:[%s], result:[%d]", joinPoint.getSignature().getName(), result);
    }

    /**
     * JoinPoint必须出现在参数列表的第一位
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void logException(JoinPoint joinPoint, Exception exception) {
        System.out.printf("logException, method:[%s], exception:[%s]", joinPoint.getSignature().getName(), exception);
    }

    @Around(value = "pointCut()")
    public Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.printf("logAround, before method:[%s] execute\n", proceedingJoinPoint.getSignature().getName());
        try {
            return proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            System.out.printf("logAround, in exception, method:[%s] execute\n",
                    proceedingJoinPoint.getSignature().getName());
            return null;
        }
    }

    private String getParameterNameWithValue(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        String methodName = methodSignature.getMethod().getName();
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = methodSignature.getParameterNames();

        StringBuilder builder = new StringBuilder(args.length + 1);
        builder.append("MethodName:").append(methodName).append(" Parameters: ");

        for (int i = 0; i < parameterNames.length; i++) {
            String parameterName = parameterNames[i];
            String parameterValue = args[i].toString();
            builder.append(parameterName)
                    .append(":")
                    .append(parameterValue)
                    .append(" ");
        }
        return builder.toString();
    }

}

package com.woods.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.woods.aop.LogAspect;
import com.woods.aop.MathCalculator;

/**
 * 配置类
 */
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAop {

    @Bean
    public MathCalculator mathCalculator() {
        return new MathCalculator();
    }

    @Bean
    public LogAspect logAspect() {
        return new LogAspect();
    }
}

package com.woods.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.woods.aop.MathCalculator;
import com.woods.config.MainConfigOfAop;

/**
 * 测试类
 */
public class IocAopTest {

    @Test
    public void testAop() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAop.class);
        MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
        // CglibAopProxy的intercept方法执行
        mathCalculator.divide(2, 1);
        logger.info("mathCalculator doneeeee ");
        // 注意不能自己new MathCalculator().divide(1, 2),这不是Spring托管的实例,因此不会走切面
    }
}

2 AOP概念介绍

首先需要明确的是AOP(Aspect-oriented Programming,面向切面编程)不是Spring提出的概念,而是一种编程的理念,与OOP类似。
总体来讲,AOP做的事情就是在我们某些类中的某些方法执行前后,插入一些公共的逻辑。例如我们想在类A的方法methodA和和类B的方法methodB执行前插入一些公共的逻辑,例如打印一下审计日志,那么就可以定义一个切面,作用于类A和类B,从而实现公共的逻辑,避免重复编码。
AOP涉及到一些常见的概念,这里我们结合上面的示例来简单介绍下。

  • Aspect,切面。能够切入多个类的具有某种功能的模块,由切点和通知构成,可以通过xml中的aop:config或@Aspect注解声明。在上面的示例代码中,LogAspect就是一个切面,其中我们定义了切点pointCut以及通知方法logStart、logEnd等。
  • JoinPoint,连接点。程序执行过程中的某个点,例如一个方法的执行或者一个异常的处理。在SpringAOP中,连接点就是表示一个方法的执行。在上面的示例代码中,我们在定义切点pointCut时,public int com.woods.aop.MathCalculator.*(…))就代表了一个连接点,也就是MathCalculator的所有方法。
  • PointCut,切点。一个切点由多个连接点构成,例如在上面的示例代码中,我们定义的切点pointCut
  • Advice,通知。在某个特定的连接点,切面执行的动作。通知包括around、before、after。例如在上面的实例程序中,我们定义的logStart、logEnd等。

3 SpringAOP实现概述

总体来讲,通过使用@EnableAspectJAutoProxy注解,向容器中添加了一个AnnotationAwareAspectJAutoProxyCreator。AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,因此在创建需要被切面切入的单实例Bean时(示例中的MathCalculator),AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization会为目标对象创建一个基于CGLIB或JDK动态代理的代理对象,我们之后通过getBean方法从Spring容器中获取MathCalculator时,拿到的就是代理对象了,调用divide方法时也是调用的代理对象被增强过的方法。
大体流程如下。

  • 通过在配置类上增加@EnableAspectJAutoProxy注解开启了SpringAOP的功能,即为切面作用的类生成代理对象,这个代理对象可以通过CGLIB或JDK动态代理来生成

  • 在@EnableAspectJAutoProxy注解中,通过@Import(AspectJAutoProxyRegistrar.class)引入了AspectJAutoProxyRegistrar

  • AspectJAutoProxyRegistrar向BeanFactory中注册了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition。这个步骤在refresh方法中的invokeBeanFactoryPostProcessors中完成。对invokeBeanFactoryPostProcessors方法的解析,详见invokeBeanFactoryPostProcessors

  • IoC容器初始时,在AbstractApplicationContext的refresh方法中的registerBeanPostProcessors方法中,会将BeanDefinition转化成Bean实例,从而拦截后续单实例Bean的创建

  • AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,在实例化目标对象时(被切面切入的类的实例,例如示例中的MathCalculator实例),Spring调用AnnotationAwareAspectJAutoProxyCreator的
    postProcessAfterInitialization为目标对象生成了代理对象

  • 后续从容器中getBean时,获取的就是代理对象了。在调用代理对象的方法时,Spring会把通知封装成拦截器,在方法调用前后就行拦截,从而实现Spring的功能。

4 SpringAOP源码分析

在测试类中,我们通过applicationContext.getBean(MathCalculator.class)获取了一个MathCalculator的实例,注意这个时候获取的实例已经是一个Spring为我们生成的代理对象了,因此在调用mathCalculator.divide(2, 1)方法时,Spring可以拦截方法的执行。那么问题来了,Spring是通过何种方式为我们生成代理对象的呢?这要从@EnableAspectJAutoProxy注解说起。

4.1 @EnableAspectJAutoProxy注解

首先看下@EnableAspectJAutoProxy注解的定义,该注解中的proxyTargetClass如果只为true,则使用CGLIB动态代理,否则Spring会在CGLIB动态代理和JDK动态代理中二选一。

package org.springframework.context.annotation;

/**
 * Enables support for handling components marked with AspectJ's {@code @Aspect} annotation,
 * similar to functionality found in Spring's {@code <aop:aspectj-autoproxy>} XML element.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see org.aspectj.lang.annotation.Aspect
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

4.2 将AnnotationAwareAspectJAutoProxyCreator转化成BeanDefinition

@EnableAspectJAutoProxy中标注了@Import注解,说明要向Spring容器中导入配置类,我们知道@Import中可以是Class、ImportSelector接口实现类、ImportBeanDefinitionRegistrar接口的实现类。可以看到这里Import的是AspectJAutoProxyRegistrar.class,它实现了ImportBeanDefinitionRegistrar接口,我们接着看下这个类。
AspectJAutoProxyRegistrar的作用是向BeanFactory中注册了一个AnnotationAwareAspectJAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator是一个BeanPostProcessor,我们为目标类生成代理对象就是由AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization方法完成的。

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) {

		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);
			}
		}
	}

}
@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
	}

看到这里终于出现AnnotationAwareAspectJAutoProxyCreator类了,SpringAOP产生的代理对象就是由该类生成的。

@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

下面是将AnnotationAwareAspectJAutoProxyCreator转化成BeanDefinition,注册到BeanFactory中的代码。

@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 beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

那么问题来了,Spring容器是在什么时候执行的AspectJAutoProxyRegistrar的registerBeanDefinitions方法的呢?
想知道这个很简单,我们在下面这行打上断点即可。

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

在这里插入图片描述
可以看到,在初始化AnnotationConfigApplicationContext时,执行到了AbstractApplicationContext的refresh方法中的invokeBeanFactoryPostProcessors方法。对invokeBeanFactoryPostProcessors方法的解析,我们已经在invokeBeanFactoryPostProcessors这篇文章中讲过了。这里针对SpringIoC容器是如何处理的@Import中的ImportBeanDefinitionRegistrar再介绍一下。

invokeBeanFactoryPostProcessors执行时,最终调用的是ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法,该方法完成了对配置类的扫描,在上面的示例代码中配置类是mainConfigOfAop。
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法对ImportBeanDefinitionRegistrar的处理过程如下所示。

  • ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

  • ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(configClasses),将配置类封装在configClasses集合中,BeanDefinitionReader将configClasses转化成BeanDefinition

  • ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()),从configClass中拿到所有实现ImportBeanDefinitionRegistrar接口的集合,

  • 调用ImportBeanDefinitionRegistrar接口集合中的每个实现类的registerBeanDefinitions方法,从而最终调用到了AspectJAutoProxyRegistrar的registerBeanDefinitions,完成了AnnotationAwareAspectJAutoProxyCreator这个BeanPostProcessor转化成BeanDefinition的过程。

到目前为止,我们已经知道了AnnotationAwareAspectJAutoProxyCreator这个为目标对象生成代理对象的类是如何转化成BeanDefinition的了,下一步就看一下这个BeanDefinition是在何时变成一个Bean的。

4.2 将AnnotationAwareAspectJAutoProxyCreator的BeanDefinition转化成Bean

SpringIoC容器的创建中我们讲过,在初始化AnnotationConfigApplicationContext的过程中,AbstractApplicationContext的registerBeanPostProcessors方法将BeanPostProcessor对应的BeanDefinition实例化成了Bean。
AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,因此是在registerBeanPostProcessors方法中下面的代码中,通过beanFactory.getBean(ppName, BeanPostProcessor.class)完成了将BeanDefinition转化成Bean的过程。
AnnotationAwareAspectJAutoProxyCreator对应的BeanName是"org.springframework.aop.config.internalAutoProxyCreator"。

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

beanFactory.getBean的具体流程我们在初始化单实例Bean中讲过。大致的流程是,首先从DefaultListableBeanFactory的单例池singletonObjects中取,如果拿不到,则新创建一个。在创建时,首先会创建一个AnnotationAwareAspectJAutoProxyCreator的实例,然后进行属性填充已经执行生命周期回调方法。经过以上步骤,Spring就把AnnotationAwareAspectJAutoProxyCreator的BeanDefinition转化成了Bean。在创建MathCalculator实例时,会调用AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization方法,生成代理对象。

4.3 为目标类(MathCalculator)生成代理对象

4.3.1 postProcessAfterInitialization执行前的方法调用路径

到目前为止,我们已经有了AspectJAwareAdvisorAutoProxyCreator这个Bean,并且它是一个BeanPostProcessor,它的父类AbstractAutoProxyCreator重写了postProcessAfterInitialization方法,在这个方法中Spring为我们创建了MathCalculator的代理对象。

在这里插入图片描述

我们在AbstractAutoProxyCreator的postProcessAfterInitialization打上断点,可以看到在初始化AnnotationConfigApplicationContext时,在AbstractApplicationContext的finishBeanFactoryInitialization方法中(我们在初始化单实例Bean中详细介绍过该方法),在执行Bean的生命周期回调,即应用BeanPostProcessor的postProcessAfterInitialization时,调用了AbstractAutoProxyCreator的postProcessAfterInitialization,为MathCalculator生成了代理对象。

在这里插入图片描述

4.3.2 postProcessAfterInitialization的执行

AbstractAutoProxyCreator的postProcessAfterInitialization方法,为目标对象MathCalculator创建了代理对象。我们看下该方法的源码。
该方法传入bean就是还没被代理的MathCalculator对象,返回的是通过CGLIB或JDK动态代理生成的代理对象。

	/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 创建代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

在wrapIfNecessary方法中,比较重要的两行代码是getAdvicesAndAdvisorsForBean以及createProxy。

getAdvicesAndAdvisorsForBean方法主要是获取所有的通知方法,createProxy则是为目标对象创建代理对象的方法。下面分别来看下。

/**
	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
	 * @param bean the raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取当前bean的所有增强器(通知方法)
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			// 将当前的beanName保存到advisedBeans中
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 创建代理对象,Spring自动决定用jdk动态代理还是cglib动态代理
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
  • getAdvicesAndAdvisorsForBean方法。getAdvicesAndAdvisorsForBean方法主要是获取所有的通知方法,即前面示例中被@Before、@After、@AfterReturning、@AfterThrowing、@Around注解标注的通知方法,它们被封装Advisor对象。
protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
/**
	 * Find all eligible Advisors for auto-proxying this class.
	 * @param beanClass the clazz to find advisors for
	 * @param beanName the name of the currently proxied bean
	 * @return the empty List, not {@code null},
	 * if there are no pointcuts or interceptors
	 * @see #findCandidateAdvisors
	 * @see #sortAdvisors
	 * @see #extendAdvisors
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}
  • createProxy。创建代理对象时,最终是通过proxyFactory.getProxy创建的。该方法最终会调用到DefaultAopProxyFactory中的createAopProxy方法,该方法中决定了使用CGLIB还是JDK动态代理来为我们创建代理对象。到这里,Spring已经为我们的MathCalculator创建好了代理对象。
/**
	 * Create an AOP proxy for the given bean.
	 * @param beanClass the class of the bean
	 * @param beanName the name of the bean
	 * @param specificInterceptors the set of interceptors that is
	 * specific to this bean (may be empty, but not null)
	 * @param targetSource the TargetSource for the proxy,
	 * already pre-configured to access the bean
	 * @return the AOP proxy for the bean
	 * @see #buildAdvisors
	 */
	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);
			}
		}

		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());
	}
@Override
	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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

5 代理对象方法的执行

经过前面的步骤,Spring已经为我们的MathCalculator对象创建出了基于CGLIB的代理对象,我们从ApplicationContext中getBean(MathCalculator.class)时,拿到的就是这个代理对象。
在这里插入图片描述

接下来,我们执行mathCalculator的divide方法,执行该方法时,会进入到CglibAopProxy中的intercept方法。

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 chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);这行代码中,通知方法被封装成了拦截器链,
紧接着retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();这行代码将proxy等参数封装成了一个CglibMethodInvocation对象,通过调用这个对象的proceed方法完成了整个方法的调用,我们看下proceed方法。

interceptorsAndDynamicMethodMatchers就是我们的通知方法,

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;
			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.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

在这里插入图片描述
最终的方法调用顺序如下,执行顺序则是从下至上的。

  • ExposeInvokcationInterceptor.invoke
  • org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke
  • org.springframework.aopaspectj.AspectJAfterReturningAdvice.invoke
  • org.springframework.aop.aspectj.AspectJAfterAdvice.invoke
  • org.springframework.aop.aspectj.AspectJAroundAdvice.invoke
  • MethodBeforeAdviceInterceptor

SpringFramework系列目录

SpringFramework系列目录

猜你喜欢

转载自blog.csdn.net/sodawoods/article/details/107443085