1.概述
在之前的博客中讲过了SpringBoot的自动装配原理,这里看SpringBoot中aop的自动装配
上篇博客地址:
在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">
* @Configuration
* @EnableAspectJAutoProxy
* public class AppConfig {
*
* @Bean
* public FooService fooService() {
* return new FooService();
* }
*
* @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">
* @Aspect
* public class MyAspect {
*
* @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">
* @Configuration
* @EnableAspectJAutoProxy(proxyTargetClass=true)
* public class AppConfig {
* // ...
* }</pre>
*
* <p>请注意,{code Aspect} bean 可以像任何其他bean一样进行组件扫描。
* 只需使用 {code Aspect} 和 {code Component} 标记方面:
*
* <pre class="code">
* package com.foo;
*
* @Component
* public class FooService { ... }
*
* @Aspect
* @Component
* public class MyAspect { ... }</pre>
* <p>
* Then use the @{@link ComponentScan} annotation to pick both up:
*
* <pre class="code">
* @Configuration
* @ComponentScan("com.foo")
* @EnableAspectJAutoProxy
* public class AppConfig {
*
* // no explicit @Bean 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