Spring Boot自动装配原理初探

Posted 风在哪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot自动装配原理初探相关的知识,希望对你有一定的参考价值。

Spring Boot自动装配原理初探

Spring Boot自动装配主要是通过注解实现的,我们直到,Spring Boot启动类会有这样一个注解:@SpringBootApplication。在这个注解里面,除了Java的元注解以外,还有三个spring自定义的注解,分别是:

  • @SpringBootConfiguration:标识该类是spring的配置类,是对@Configuration注解的包装
  • @EnableAutoConfiguration:这是自动装配的关键注解,本文主要就是介绍这个注解
  • @ComponentScan:配置包扫描规则,在该注解中指定的扫描包下的bean对象会被注册到spring容器中

通过这三个注解我们可以发现,Spring Boot自动装配主要是通过@EnableAutoConfiguration注解实现的。

@EnableAutoConfiguration

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

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

   /**
    * 根据类型排除不会被使用的自动装配类
    */
   Class<?>[] exclude() default {};

   /**
    * 根据类名称排除不会被使用的自动装配类
    */
   String[] excludeName() default {};

}

通过源码我们可以发现,@EnableAutoConfiguration注解除了包含了元注解以外,还包含@AutoConfigurationPackage注解和@Import注解。这两个注解分别是什么作用呢:

  • @AutoConfigurationPackage:它其实还是使用的@Import注解,将AutoConfigurationPackages.Registrar.class导入到spring中
  • @Import:主要用于导入一些配置类或者自定义的普通类到spring容器中,这里就是向spring容器中导入了AutoConfigurationImportSelector.class

@AutoConfigurationPackage

该注解的主要作用就是向spring容器中导入AutoConfigurationPackages.Registrar.class,那么这个类主要用来做什么呢?

这是AutoConfigurationPackages类的内部类,我们来看看它的作用。

AutoConfigurationPackages.Registrar

这个类主要作用就是向spring容器导入一系列组件,它是将指定包下的所有组件导入spring容器的。

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
   
   /**
   * AnnotationMetadata代表了注解标在了哪个类上,它的属性值都有哪些,可以通过端点调试来看看
   */
   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      // new PackageImports将注解的元数据进行包装,并获得注解标注的类所处的包
      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImports(metadata));
   }

}

可以发现这个注解就是标注在spring boot的主启动类上面。

image-20210501172040764

可以发现new PackageImports(metadata).getPackageNames()就是为了获取spring boot主启动类所处的包,然后调用register方法注册自动配置的包名。
在这里插入图片描述

这里主要是注册了AutoConfigurationPackages的内部类BasePackages。

在这里插入图片描述

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector类专门用于自动装配。

这里主要调用了该类的selectImports方法导入自动配置类:

在这里插入图片描述

而selectImports方法又调用了getAutoConfigurationEntry方法进行了实际的导入操作,可以在这个方法上打个断点进行调试。

可以发现,这里通过调用getCandidateConfigurations方法获得了自动装配类的类名,所以这个方法很关键。

在这里插入图片描述

getCandidateConfigurations方法

该方法主要用于导入自动装配的类的全部类名,在其中又调用了SpringFactoriesLoader.loadFactoryNames方法,这个方法就是实际的获取自动装配类的类名的方法,这个方法在spring启动的时候也会用到。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
         getBeanClassLoader());
   Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
         + "are using a custom packaging, make sure that file is correct.");
   return configurations;
}

loadSpringFactories方法

loadFactoryNames方法实际调用的就是loadSpringFactories方法,这个方法读取了资源文件并从中提取了自动装配相关类的信息。
在这里插入图片描述

可以在这个方法上面打断点继续调试,此时会在selectImports方法之前执行loadSpringFactories方法,从META-INF/spring.factories文件中获取自动装配的类,并加载到cache缓存中,当通过selectImports方法进入的时候会直接从这个缓存获取对应的类名。

此时会扫描我们项目中依赖的所有jar包中所有的META-INF/spring.factories文件

image-20210501184558886

对于自动装配来说,使用到的META-INF/spring.factories就是spring-boot-autoconfigure-2.3.4.RELEASE.jar包下的该文件,在spring.factories文件中给定了spring容器一启动就要给容器中加载的所有配置类。

在这里插入图片描述

当然,除此之外还有其他的与spring-boot整合的相关的自动配置类也是通过这种方法从spring.factories文件中导入spring容器的,例如当我们使用mybatis与spring-boot整合时也会导入其自动配置类。

在这里插入图片描述

当spring boot项目启动时,会将所有的自动装配类加载到容器中,但是并不是所有的自动装配都生效。看下文分析。

按需开启自动配置类

AopAutoConfiguration

AopAutoConfiguration类用于控制aop的自动装配。

首先,通过@Configuration标识该类是一个配置类,然后通过@ConditionalOnProperty注解判断在application.properties中是否存在对应的配置,这里是判断spring.aop.auto的值是否为为true,这里如果不配置的话默认为true,只有为true时这个自动配置类才生效。

image-20210501191517902

image-20210501192202621

从这里我们可以发现:,自动配置的开启主要就是根据@Conditional注解来实现的,@Conditional就是根据某个类存在或者不存在,某个Bean存在或者不存在,某个属性存在或者不存在来决定加载哪些配置类。

CacheAutoConfiguration

在这里插入图片描述

  • @Configuration:表示这是一个配置类

  • @ConditionalOnClass:只有当CacheManager.class存在时,该自动装配类才起作用

  • @ConditionalOnBean:只有当CacheAspectSupport对应的bean存在时,该自动装配类才起作用

  • @ConditionalOnMissingBean:只有当不存在名为"cacheResolver"的bean时,该自动配置类才起作用

  • @EnableConfigurationProperties:将@ConfigurationProperties注解的类注入spring容器中,通过这个配置类可以读取application.yml配置的内容,并在spring容器内部使用,这个注解是我们在application.yml文件中进行配置的关键。

    从源码可以看出,CacheProperties会读取以spring.cache为前缀的配置

在这里插入图片描述

  • @AutoConfigureAfter:表示该自动配置类必须在加载完指定的四个自动装配类之后才能加载

  • @Import:导入了辅助类

image-20210501204223723

从这里我们可以发现我们自定义的bean可以覆盖spring boot为我们定义的bean。当然我们可以通过application.yml配置对默认的配置进行改动,而不用自己再进行配置。

spring boot的自动装配也依赖了@EnableConfigurationProperties和@ConfigurationProperties这两个注解,将用户在application.yml中的配置应用到程序中。

总结

image-20210501204223723

  1. 在我们启动spring boot项目时,spring boot会自动为我们加载所有的启动配置类xxxAutoConfiguration
  2. 根据给定的条件确定配置类是否生效,默认会绑定配置文件指定值,xxxxProperties绑定了给定前缀的配置文件,所以这里会直接从这里面获取配置文件的指定值
  3. 生效的配置类就会向容器中装配组件,容器中存在这些组件后就相当于有了这些功能
  4. 如果我们需要定制化配置:
    • 直接使用@Bean注解配置自己的bean替换底层的组件
    • 通过查看这个组件获取的配置,然后在application.yml修改相应的配置值即可

欢迎访问我的个人博客:风在哪个人博客

以上是关于Spring Boot自动装配原理初探的主要内容,如果未能解决你的问题,请参考以下文章

spring boot中的底层配置文件application.yam(application.property)的装配原理初探

SpringBoot的自动装配原理

spring boot自动装配原理

spring boot自动装配原理@EnableAutoConfiguration

Spring Boot 自动装配定义与自定义starter原理,及如何实现自定义装配

Spring Boot 自动装配定义与自定义starter原理,及如何实现自定义装配