springboot自动装配原理

SpringBoot的自动装配是通过@Import(AutoConfigurationImportSelector.class)注解工作,它读取spring.factories文件中的配置,结合spring-autoconfigure-metadata.properties过滤并加载所需的XXXAutoConfiguration类。这个过程涉及到条件匹配,如OnBeanCondition、OnClassCondition和OnWebApplicationCondition等过滤器,确保只有满足条件的类才会被添加到容器中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

springboot的自动装配是其重要特性之一,在使用中我们只需在maven中引入需要的starter,然后相应的Bean便会自动注册到容器中。例如:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
@Resource
private RabbitTemplate rabbitTemplate;

此时我们便可以注入rabbitTemplate使用相应的功能了。本篇文章将探究springboot如何实现的自动装配(基于2.2.5.RELEASE)。

@EnableAutoConfiguration

在@SpringBootAppilication的注解上有一个@EnableAutoConfiguration注解,这个注解完成了自动装配的功能。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   /**
    * Exclude specific auto-configuration classes such that they will never be applied.
    * @return the classes to exclude
    */
   Class<?>[] exclude() default {};

   /**
    * Exclude specific auto-configuration class names such that they will never be
    * applied.
    * @return the class names to exclude
    * @since 1.3.0
    */
   String[] excludeName() default {};

}

@EnableAutoConfiguration通过@Import注解将AutoConfigurationImportSelector中selectImports方法返回的类注册到容器中。@EnableAutoConfiguration 会尝试猜测并配置那些你需要的bean。通常根据classpath和你定义的bean来决定注册哪些类。例如,如果你的classpath有tomcat-embed相关的jar,那么你就可能想要TomcatServletWebServerFactory这个类的实例。
因为当使用@SpringBootApplication时自动装配就会自动生效,所以再使用这个注解将不会再起作用。
自动装配bean的过程将在用户自定义的bean被注册到容器之后进行
每个starter对应一个XXXAutoConfiguration类,其中定义了一些需要的bean

如何不让某些类自动装配

  1. 可以通过exclude属性将那些不想自动装配的类排除在外
  2. 如果你不能访问那些想排除的类可以使用exclueName属性指定类全名
  3. 也可以使用spring.autoconfigure.exclude.property属性

AutoConfigurationImportSelector

selectImports()

将selectImports方法重写为:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
         annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
  1. 入参AnnotationMetadata里面记录着@Import注解的元数据,例如该注解所标记的类
  2. 判断自动装配是否关闭,如果关闭就返回空数组,自动装配可以通过spring.boot.enableautoconfiguration=false关闭,默认是开启,关闭后将无法自动装配
  3. 加载AutoConfigurationMetadata,其实就是将META-INF/spring-autoconfigure-metadata.properties文件下的属性加载进来,过滤时使用。

存储着待自动装配候选类的过滤计算规则,框架会根据文件中的规则逐个判断候选类是否需要自动装配进容器 作用TODO

  1. 调用getAutoConfigurationEntry获取需要加载入容器的类

getAutoConfigurationEntry()

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                                           AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}
  1. 获得@EnableAutoConfiguration注解的属性,即exclude和excludeName属性的值
  2. 获得那些可能会被考虑的XXXAutoConfiguration类的类名,从META-INF/spring.factory的org.springframework.boot.autoconfigure.EnableAutoConfiguration属性获得
  3. 将获得的XXXAutoConfiguration类名去重
  4. 去掉1中获得的exclude和excludeName属性中的类,另外将配置文件中的spring.autoconfigure.exclude属性配置的类也去掉
  5. 过滤
  6. 触发自动配置事件

filter()

过滤即是通过规则将待注入的AutoConfiguration类进行筛选,将符合条件的留下。过滤的过程如下:

private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        invokeAwareMethods(filter);
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;
                skipped = true;
            }
        }
    }
    if (!skipped) {
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }
    if (logger.isTraceEnabled()) {
        int numberFiltered = configurations.size() - result.size();
        logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                     + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
    }
    return new ArrayList<>(result);
}
  1. 入参configurations为待过滤的所有AutoConfigration类,autoConfigurationMetadata为过滤规则
  2. getAutoConfigurationImportFilters()找出spring.factory中org.springframework.boot.autoconfigure.AutoConfigurationImportFilter对用的属性值作为过滤器,包括以下三个:
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

如果有哪个XXAutoConfiguration类没有通过过滤,则剔除出去。
下面将介绍这3个过滤器的作用:

  1. OnClassCondition 指定的类在已经被加载到jvm中,通过classLoader.loadClass(className)或Class.forName(className)获取到类即可
  2. OnBeanCondition 指定的bean已经被加载到容器中
  3. OnWebApplicationCondition 当是某种web应用时才能通过条件,目前都是SERVLET类型的web应用

以OnClassCondition为例,其核心代码为:

private ConditionOutcome getOutcome(String candidates) {
    try {
    if (!candidates.contains(",")) {
        return getOutcome(candidates, this.beanClassLoader);
    }
    for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
        ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
        if (outcome != null) {
            return outcome;
        }
    }
}
catch (Exception ex) {
    // We'll get another chance later
}
return null;
}
private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
    if (ClassNameFilter.MISSING.matches(className, classLoader)) {
        return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
                                        .didNotFind("required class").items(Style.QUOTE, className));
    }
    return null;
}

getOutCome即是获取匹配结果的方法,最终通过ClassNameFilter.MISSING.matches(className, classLoader)使用反射获得是否有类加载到jvm中

protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
   if (classLoader != null) {
      return classLoader.loadClass(className);
   }
   return Class.forName(className);
}

总结

springboot的自动装配本质上是通过@Import(AutoConfigurationImportSelector.class)注解将spring.factories文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration属性下的XXXAutoConfig类加载到容器中,当然不是全部加载,要通过spring-autoconfigure-metadata.properties文件下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值