栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

05-Spring环境下AOP运行原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

05-Spring环境下AOP运行原理

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 targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
	
	//保存需要被AOP拦截的Bean的名称与它的代理对象Class类型的映射关系
	private final Map> proxyTypes = new ConcurrentHashMap<>(16);
	
	//保存Bean是否需要被AOP拦截,如果需要拦截value为true,否则为false
	private final Map 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的代理对象并返回,之后的逻辑就和之前文章分析过的代理过程一样了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434872.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号