Spring源码-AOP(五)-AOP核心组件的注册

上一篇已经说过AOP的入口是BeanDefinition。在

中,解析的是AopNamespaceHandler类,我们对 AopNamespaceHandler 类进行分析。

AspectJAutoProxyBeanDefinitionParser

我们发现有这样一段代码

registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
也就是说
AspectJAutoProxyBeanDefinitionParser 这个类会去解析

标签,进入到该类中发现它也是BeanDefinitionParser的实现类,而所有BeanDefinitionParser的实现类都是从parse()开始入口的。那么我们接下来看看这个类

【AspectJAutoProxyBeanDefinitionParser】

public BeanDefinition parse(Element element, ParserContext parserContext) {
	//注册AnnotationAwareAspectJAutoProxyCreator
	AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
	//对于注释中的子类进行解析
	extendBeanDefinition(element, parserContext);
	return null;
}

其中的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法是实现注册AnnotationAwareAspectJAutoProxyCreator的地方,也是AOP注册逻辑的主要逻辑。

【AOPNameSpaceUtils】

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		ParserContext parserContext, Element sourceElement) {
	/**
	 * 1、注册或者升级AutoProxyCreator
	 * 2、定义beanName为org.Springframework.aop.config.internalAutoProxyCreator的
	 * BeanDefinition
	 */
	BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	// 对于 proxy-target-class 以及 expose-proxy 属性的处理
	useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
	// 注册组件并通知,便于监听器作进一步处理
	// 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreator
	registerComponentIfNecessary(beanDefinition, parserContext);
}

1、注册AnnotationAwareAspectJAutoProxyCreator

我们进入到registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法内部

/**
 * 1、实现了自动注册AnnotationAwareAspectJAutoProxyCreator类的功能
 * 2、处理优先级问题,如果已经存在了自动代理创建器,且已经存在的自动代理创建器与现在的不一致,
 * 那么需要根据优先级来判断到底需要使用哪个
 */
@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)) {
		//AUTO_PROXY_CREATOR_BEAN_NAME = org.springframework.aop.config.internalAutoProxyCreator
		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) {
				//改变bean的ckassName属性(改变bean最重要的就是改变该属性)
				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;
}
  • 1、该方法主要是实现了自动注册AnnotationAwareAspectJAutoProxyCreator类的功能,该类是AOP的核心类。
  • 2、处理优先级问题,如果已经存在了自动代理创建器,且已经存在的自动代理创建器与现在的不一致,那么需要根据优先级来判断到底需要使用哪个

2、属性处理

回到registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中继续接下来的分析useClassProxyingIfNecessary()方法,这里是对proxy-target-class及expose-proxy属性的处理。

【AopNamespaceUtils】

/**
 * 该方法实现了对proxy-target-class属性以及expose-proxy 属性的处理
 * @param registry
 * @param sourceElement
 */
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
	if (sourceElement != null) {
		//对于proxy-target-class属性的处理
		boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
		if (proxyTargetClass) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		//对于expose-proxy属性的处理
		boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
		if (exposeProxy) {
			//强制使用,也是属性设置的一种方式
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
}

AopConfigUtils中的强制设置

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

在此处两个属性的作用如下:

  • 1、prioxy-target-class: 主要负责上面两种代理的实现,SpringAOP使用jdkProxy或者CGLIB为目标对象创建代理(尽量使用jdkProxy),如果被代理的目标对象实现了至少一个接口,则会使用jdk动态代理。所有该目标类型实现的接口都将被代理。若该mybatis对象没有实现任何接口。则创建一个CGLIB代理,如果你希望强制使用CGLIB代理(即增强代理目标所有方法)。但是有如下两个问题:

    • 无法通知(advice)Final方法,因为它们不能被覆盖。
    • 需要将CGLIB二进制包放在classpath下面。
  • 2、expose-proxy 则负责自我调用切面中的增强。

    以上就完成了AspectJAutoProxyBeanDefinitionParser对象的注册


谢谢你请我吃糖果

Spring源码-AOP(五)-AOP核心组件的注册 微信

原文 

http://sunliangliang.com/2017/09/05/Spring源码-AOP-五-AOP核心组件的注册/

PS:如果您想和业内技术大牛交流的话,请加qq群(527933790)或者关注微信公众 号(AskHarries),谢谢!

转载请注明原文出处:Harries Blog™ » Spring源码-AOP(五)-AOP核心组件的注册

赞 (0)

分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址