05-Spring环境下AOP运行原理

  • Post author:
  • Post category:其他




Spring环境下AOP运行原理

​ 前面文章已经分析了

SpringAop

原生的运行原理,本节将分析使用频率最高场景:

Spring

环境下的

AOP

运行原理。本文会涉及到

Spring

启动期间注入

Bean

的流程,默认你已经非常熟悉了,本文不再详细赘述相关流程。



SpingBoot

项目中使用

AOP

一般会做如下操作:

  • 主启动类上添加

    @EnableAspectJAutoProxy

    注解开启

    SpringAop

    功能
  • 自定义切面并注入到

    Spring

    中即可
@SpringBootApplication
@EnableAspectJAutoProxy
public class TestApplication {

	public static void main(String[] args) {
		SpringApplication.run(TestApplication.class, args);
	}
}

@Aspect
@Component
public class TestAspect {

    @Pointcut(value = "execution(* com.ssm.test.aop.ATMService.withdrawMoney())")
    public void pointcut() {}

    @Before(value = "pointcut()")
    public void before() {
        System.out.println("TestAspect.before.....");
    }

    @After(value = "pointcut()")
    public void after() {
        System.out.println("TestAspect.after.....");
    }
}

@Service
public class ATMService implements BankService {
    @Override
    public void withdrawMoney() {
        System.out.println("ATMService : 取钱成功");
    }
}

如上代码所示是一个简单的

AOP

增强案例,本节就基于这个案例分析

Spring

环境下

AOP

的运行原理。


原理分析




@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	boolean proxyTargetClass() default false;
	
	boolean exposeProxy() default false;
}

首先分析下在主启动类上添加的的

@EnableAspectJAutoProxy

注解 , 该注解主要是用于配置

proxyTargetClass、exposeProxy

属性,这个两个属性在之前的文章也分析过了,此处不再赘述。如上图源码所示该注解还有有一个非常关键的作用 :

@Import(AspectJAutoProxyRegistrar.class)

, 了解过

Spring

原理可以知道这边

@Import

注解是用来注入

AspectJAutoProxyRegistrar

这个

Bean

的.




AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

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

如上图源码所示,

AspectJAutoProxyRegistrar



BeanDefinitionRegistry

作为参数将主要逻辑都委托给了

AopConfigUtils

这个工具类。

BeanDefinitionRegistry

接口并不陌生,主要提供

注册、删除、获取Bean

的功能,所以可以大致判断出

AopConfigUtils

在这边主要是注入了某个

Bean

:




AopConfigUtils

public abstract class AopConfigUtils {
	
		
	//The bean name of the internally managed auto-proxy creator.
	public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";
		
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
	}
	
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}
		
	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);
		//将当前要注入的Bean的优先级设置为最高
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}
	
	public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
		}
	}

	public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
		}
	}
	
	.....
			
}

结合上图源码可知

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

这行代码实际上是手动向

Spring

注入了

beanName



org.springframework.aop.config.internalAutoProxyCreator

,

Bean类型为 : AnnotationAwareAspectJAutoProxyCreator.class



Bean

. 有个细节需要注意:

registerOrEscalateApcAsRequired()

方法注入

Bean

时会为该

Bean

设置

order

属性,将

Bean

的优先级调整为最高级别,这样做的目的是可以优先注入该

Bean

, 但优先注入这个

Bean

具体有何意义此处先

Mark

一下。


forceAutoProxyCreatorToUseClassProxying()、forceAutoProxyCreatorToExposeProxy()

两个方法实际上是为上面注入的

AnnotationAwareAspectJAutoProxyCreator

这个Bean设置

proxyTargetClass、exposeProxy

属性值。虽然

@EnableAspectJAutoProxy

注解中这两个属性值默认值为

false

, 但是底层源码却直接将属性值置为了

true

, 从而可以知道

SpringBoot

中使用

SpringAop

默认会使用强制使用

CGLIB

代理,并且会将当前的代理对象暴露在当前线程中,可以直接使用

AopContext

获取到当前代理对象。

综上所述可以总结出: 主启动类上添加

@EnableAspectJAutoProxy

这个注解可以向

Spring

中注入

AnnotationAwareAspectJAutoProxyCreator

这个

Bean

, 具体它是用来干嘛的此处先不表,下面会详细分析它。




AnnotationAwareAspectJAutoProxyCreator

如上图所示是

AnnotationAwareAspectJAutoProxyCreator



UML

图,由于涉及的比较多所以分析时只会贴出关键代码。上图可以很清楚的看出

AnnotationAwareAspectJAutoProxyCreator

实现了

BeanPostProcessor、InstantiationAwareBeanPostProcessor

接口,所以本质上是一个

BeanPostProcessor

. 对

Spring

了解的同学应该都知道

Spring

在启动期间注入

Bean

时,会使用

IOC

中的

BeanPostProcessor

类型的

Bean

对当前

Bean

的注入做增强处理(相当于是一个埋点处理), 我们简单贴个代码回顾一下 :

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
		
		
	......
	
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

		try {
		//Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException("", ex);
		}
	}
	
	
	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
	
		......
		
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//调用BeanPostProcessor接口中的postProcessBeforeInitialization方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException("Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
		//调用BeanPostProcessor接口中的postProcessAfterInitialization方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}


    
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					//调用BeanPostProcessor接口InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
					//调用BeanPostProcessor接口中的postProcessAfterInitialization方法
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}
	
    ......
}

如上图所示是

Spring

遍历注入一个

Bean

时会调用到

AbstractAutowireCapableBeanFactory#createBean()

方法,在这个方法中有这样一行代码 :

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

这行代码上有一行非常重要的注释 :

给BeanPostProcessor一个机会返回代理实例而不是目标实例

。 仔细观察

resolveBeforeInstantiation()

方法逻辑可以看到它主要是遍历调用

IOC

中所有的

BeanPostProcessor



postProcessBeforeInstantiation

方法(该方法属于

InstantiationAwareBeanPostProcessor

)和

postProcessAfterInitialization

方法(该方法属于

BeanPostProcessor

).


createBean

还会委托到

AbstractAutowireCapableBeanFactory#initializeBean()

方法 :

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		
		......

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			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()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

这个方法会在执行

Spring

初始化方法

afterPropertiesSet

前后分别遍历调用

IOC

中所有

BeanPostProcessor



postProcessBeforeInitialization



postProcessAfterInitialization

方法。

根据上面

AnnotationAwareAspectJAutoProxyCreator

UML图可知它实现了

BeanPostProccesor和InstantiationAwareBeanPostProcessor

接口,所以我们重点关注一下它和

BeanPostProcessor

有关的接口实现 ,这些逻辑在

AnnotationAwareAspectJAutoProxyCreator

的父类

AbstractAutoProxyCreator

中 :




AbstractAutoProxyCreator

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
		
	//保存那些有指定TargetSource的Bean的名称
	private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
	
	//保存需要被AOP拦截的Bean的名称与它的代理对象Class类型的映射关系
	private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
	
	//保存Bean是否需要被AOP拦截,如果需要拦截value为true,否则为false
	private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
	
	
	//该方法是InstantiationAwareBeanPostProcessor接口中的
	//根据上面的分析可知该方法会在Spring注入每个Bean的时候都执行
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { 
			
			//这个if用于判断是否已经处理过当前Bean
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			
			//到这个if说明当前的Bean还没被处理过
			//isInfrastructureClass方法首先会判断当前Bean是否是一个切面
			//重点是shouldSkip方法,该方法第一次调用是会找到当前IOC中所有的切面,然后遍历切面判断当前的Bean是否可以被切点拦截
			//以本案例中注入ATMService为例,它不是切面但是需要被AOP拦截,所以这个if为false
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		
		//获取当前Bean对应的TargetSource实例,由于案例中没有提供ATMService的TargetSource
		//所以会这个方法会返回null结束
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		//如果有指定TargetSource则会调用createProxy方法,该方法会使用之前分析过的ProxyFacoty生成代理对象并返回
		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;
	}
	
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}
	
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}
	
	//该方法是实现的`BeanPostProcessor`接口中的
	//该方法会在Spring注入Bean期间执行afterPropertiesSet方法后执行
	//这个方法将逻辑委托给了wrapIfNecessary方法
	@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;
	}
	
	
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		
		//如果targetSourcedBeans包含当前的beanName,说明上面的postProcessBeforeInstantiation方法已经处理过这个Bean了,此处就不需要再处理
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		
		//如果当前Bean属于Advisor类型则也不需要处理
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		
		//如果当前Bean是切面或者不需要生成代理对象则直接返回
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		//到这一步就说明当前Bean有被切面拦截到所以需要生成当前Bean的代理对象以便实现AOP增强
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			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;
	}
	
	//生成当前Bean的代理对象
	//使用的是之前分析过的ProxyFactory方式生成了代理对象
	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());
	}
	
	......
    
}



流程总结


SpringBoot

集成

SpringAop

后会注入

AnnotationAwareAspectJAutoProxyCreator

这个

Bean

, 它是一个

BeanPostProcessor

类型.

Spring

在启动期间遍历注入

Bean

时会遍历调用

IOC

中所有

BeanPostProcessor

类型的

postProcessBeforeInitialization、postProcessAfterInitialization

方法。

AnnotationAwareAspectJAutoProxyCreator

也属于

BeanPostProcessor

,所以

Spring

注入每个

Bean

时也会调用到它的这个两个方法,方法是在它的父类

AbstractAutoProxyCreator

中实现的。

AbstractAutoProxyCreator

中的这两个方法会判断当前

Spring

正在注入的这个

Bean

是否需要被

IOC

中的切面拦截,如果不需要则直接返回不做任何处理,否则会调用它的

createProxy

方法使用之前文章分析过的

ProxyFactory

方式生成当前

Bean

的代理对象并返回,之后的逻辑就和之前文章分析过的代理过程一样了。



版权声明:本文为jackcheng1117原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。