SpringBoot Aop自动装配源码解析

1.概述

在之前的博客中讲过了SpringBoot的自动装配原理,这里看SpringBoot中aop的自动装配

上篇博客地址:

springboot源码分析-自动装配_LouD_dm的博客-CSDN博客_springboot源码

在spring-boot-autoconfigure里有一个spring.factories文件,关于aop自动装配的是

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

2.AopAutoConfiguration代码分析

/**
 * {链接 org.springframework.boot.autoconfigure.EnableAutoConfiguration
 * Auto-configuration} 用于 Spring 的 AOP 支持。相当于启用
 * {link EnableAspectJAutoProxy EnableAspectJAutoProxy} 在您的配置中。
 * <p>
 * 如果 {literal spring.aop.auto=false},配置将不会被激活。这
 * {literal proxyTargetClass} 属性将是 {literal true},默认情况下,但可以
 * 通过指定 {literal spring.aop.proxy-target-class=false} 覆盖。
 *
 * @author Dave Syer
 * @author Josh Long
 * @since 1.0.0
 * @see EnableAspectJAutoProxy
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
			matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}

}

这里aop自动装配的条件是 有EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class这几个类型的Bean,

同时可以在spring的配置spring.aop.proxy-target-class,如果配置true,使用Cglib的自动装配CglibAutoProxyConfiguration ,如果是false,会使用JdkDynamicAutoProxyConfiguration 

这里的作用是,如果在application.properties和application.yml中配置了spring.aop.proxy-target-class

  • true
    • Bean实现了接口使用CGLIB代理
    • Bean没有实现接口使用CGLIB代理
  • false
    • Bean实现了接口使用JDK动态代理
    • Bean没有实现接口使用CGLIB代理

由于spring.aop.proxy-target-class默认为true,所以默认是CGLIB代理

也就是CglibAutoProxyConfiguration配置会生效

额外知识点:jdk动态代理为什么要基于接口,而cglib不用

jdk动态代理是根据接口生成对应的实现类,cglib是根据类生成子类

我们来看EnableAspectJAutoProxy这个注解的代码,这里是aop自动装配的关键

3.EnableAspectJAutoProx源码

/**
 * 支持处理标有 AspectJ 的 {code Aspect} 注释的组件,
 * 类似于 Spring 的 {code <aop:aspectj-autoproxy>} XML 元素中的功能。
 * 用于 {link Configuration} 类,如下所示:
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableAspectJAutoProxy
 * public class AppConfig {
 *
 *     &#064;Bean
 *     public FooService fooService() {
 *         return new FooService();
 *     }
 *
 *     &#064;Bean
 *     public MyAspect myAspect() {
 *         return new MyAspect();
 *     }
 * }</pre>
 * <p>
 * 其中 {code FooService} 是一个典型的 POJO 组件,而 {code MyAspect} 是一个
 * {code Aspect} 风格的方面:
 *
 * <pre class="code">
 * public class FooService {
 *
 *     // various methods
 * }</pre>
 *
 * <pre class="code">
 * &#064;Aspect
 * public class MyAspect {
 *
 *     &#064;Before("execution(* FooService+.*(..))")
 *     public void advice() {
 *         // advise FooService methods as appropriate
 *     }
 * }</pre>
 * <p>
 * 在上述场景中,{code EnableAspectJAutoProxy} 确保 {code MyAspect}
 * 将被正确处理,并且 {code FooService} 将被代理混合在
 * 它贡献的建议。
 *
 * <p>用户可以控制为{code FooService}创建的代理类型使用
 * {link #proxyTargetClass()} 属性。以下启用 CGLIB 样式的“子类”
 * 代理,而不是默认的基于接口的 JDK 代理方法。
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableAspectJAutoProxy(proxyTargetClass=true)
 * public class AppConfig {
 *     // ...
 * }</pre>
 *
 * <p>请注意,{code Aspect} bean 可以像任何其他bean一样进行组件扫描。
 * 只需使用 {code Aspect} 和 {code Component} 标记方面:
 *
 * <pre class="code">
 * package com.foo;
 *
 * &#064;Component
 * public class FooService { ... }
 *
 * &#064;Aspect
 * &#064;Component
 * public class MyAspect { ... }</pre>
 * <p>
 * Then use the @{@link ComponentScan} annotation to pick both up:
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;ComponentScan("com.foo")
 * &#064;EnableAspectJAutoProxy
 * public class AppConfig {
 *
 *     // no explicit &#064Bean definitions required
 * }</pre>
 *
 * <b>注意:{code EnableAspectJAutoProxy} 仅适用于其本地应用程序上下文,
 * 允许对不同级别的 bean 进行选择性代理。</b> 请重新声明
 * {code EnableAspectJAutoProxy} 在每个单独的上下文中,例如共同根网
 * 应用程序上下文和任何单独的 {code DispatcherServlet} 应用程序上下文,
 * 如果您需要在多个级别应用其行为。
 *
 * <p>此功能需要在类路径中存在 {code aspectjweaver}。
 * 虽然该依赖项对于 {code spring-aop} 通常是可选的,但它是必需的
 * 用于 {code EnableAspectJAutoProxy} 及其底层设施。
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @see org.aspectj.lang.annotation.Aspect
 * @since 3.1
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * 指示是否要创建基于子类 (CGLIB) 的代理,而不是
	 * 到标准的基于 Java 接口的代理。默认值为 {code false}。
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 指示代理应该由 AOP 框架公开为 {code ThreadLocal}
	 * 通过 {link org.springframework.aop.framework.AopContext} 类进行检索。
	 * 默认关闭,即不保证 {code AopContext} 访问将起作用。
	 *
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

这里导入一个AspectJAutoProxyRegistrar的配置类

3.AspectJAutoProxyRegistrar源码分析

/**
 * 注册一个 {link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
 * AnnotationAwareAspectJAutoProxyCreator} 针对当前 {link BeanDefinitionRegistry}
 * 根据给定的 {link EnableAspectJAutoProxy} 注解适当。
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @see EnableAspectJAutoProxy
 * @since 3.1
 */
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * 根据值注册、升级和配置 AspectJ 自动代理创建者
	 * 导入时的 {link EnableAspectJAutoProxy#proxyTargetClass()} 属性
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//注册AspectJAnnotationAutoProxyCreator这个Bean
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		//查找EnableAspectJAutoProxy注解的配置
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			//如果有配置把配置添加到对应的BeanDefinition里
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

我们来看AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)

    static {
		// 设置优先级列表...
		APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
		APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
	}    


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

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

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

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

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		//如果之前配置了internalAutoProxyCreator
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			//internalAutoProxyCreator这个Bean不是AnnotationAwareAspectJAutoProxyCreator
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				//获取配置的优先级
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				//如果当前的优先级低于必要的优先级,修改为必要的bean的名称
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
		//没有配置创建对应的BeanDefinition
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		beanDefinition.setSource(source);
		//设置最高优先级
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		//注册bean名称是internalAutoProxyCreator,类型是AnnotationAwareAspectJAutoProxyCreator的Bean
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

    /**
	 * 查找对应的优先级
	 * @param className
	 * @return
	 */
	private static int findPriorityForClass(@Nullable String className) {
		for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
			Class<?> clazz = APC_PRIORITY_LIST.get(i);
			if (clazz.getName().equals(className)) {
				return i;
			}
		}
		throw new IllegalArgumentException(
				"Class name [" + className + "] is not a known auto-proxy creator class");
	}

如果之前有配置internalAutoProxyCreator这个Bean,根据优先级判断是否修改BeanDefinition类型为AnnotationAwareAspectJAutoProxyCreator类型,没有注解AnnotationAwareAspectJAutoProxyCreator类型的BeanDefinition,之后会根据BeanDefinition来创建Bean

下篇博客研究AnnotationAwareAspectJAutoProxyCreator

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LouD_dm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值