SpringBoot配置自动加载机制

Springboot启动流程

首先看一下Springboot的启动流程:

SpringBoot配置自动加载机制_第1张图片

配置类加载

@ComponentScan和**@Import**注解

SpringBoot配置自动加载机制_第2张图片

自动配置的关键注解是:@ComponentScan 和 @Import 注解,这两个注解的作用如下:

  • @ComponentScan
    • 对指定的package进行扫描,找到符合条件的类,默认搜索被@Component修饰的配置类
    • 通过属性basePackages或basePackageClasses来指定要进行扫描的package;如果没有指定package,则默认扫描当前@ComponentScan所修饰的类所在的package
  • @Import
    • 提供了一种显式地从其他地方加载配置类的方式,可以避免使用性能较差的组件扫描(@ComponentScan)
    • 支持三种导入方式
      • 普通类
      • 接口ImportSelector的实现类
      • 接口ImportBeanDefinitionRegistrar的实现类

针对@Import给出实例

1、导入普通类

public class ConfigA {
    @Bean
    public A a(){
       return new A();
    }
}

public class A {
    
}

// 使用配置类ConfigB将ConfigA的配置导入
@Configuration
@Import(ConfigA.class) // 导入ConfigA的配置
public class ConfigB {
    
}

2、@Import导入接口ImportSelector的实现类

接口ImportSelector中有一个selectimports方法,它的返回值是一个字符串数组,数组中的每个元素分别代表一个将被导入的配置类的全限定名;利用此特性我们可以给IOC容器动态地导入多个配置类。

public class ZooConfig {
    @Bean
    public Tiger tiger() {
        return new Tiger();
    }
}

public class Tiger {
    
}


public class ZooImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"com.xxx.config.ZooConfig"};
    }
}

@Configuration
@Import({ZooImportSelector.class})
public class ConfigSelector{
    
}

3、@Import导入接口ImportBeanDefinitionRegistrar的实现类

通过@Import导入一个ImportBeanDefinitionRegistrar接口的实现类;通过它,可以手动将多个BeanDefinition注册到IOC容器,从而实现个性化定制;利用此特性我们可以给IOC容器动态地导入多个BeanDefinition。

public class Dog{

}

public class ZooRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
        GenericBeanDefinition bd = new GanericBeanDefinition();
        bd.setBeanClass(Dog.class);
        registry.registerBeanDefinition("dog", bd);
    }
}

@Configuration
@Import({ZooRegistrar.class})
public class Config(){
    
}

Springboot的配置加载过程

SpringBoot配置自动加载机制_第3张图片

首先启动类的@SpringBootApplication注解实现了应用的启动和配置的加载。

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan("com.xlt.mapper")
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

@SpringBootApplication注解主要引入了三个注解@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,作用分别是:

  • @SpringBootConfiguration:加载 @Configuration注解的配置

  • @EnableAutoConfiguration:加载自动配置的包和通过@Import注解导入AutoConfigurationImportSelector.class

  • @ComponentScan:组件扫描

@SpringBootConfiguration // 加载Springboot配置
@EnableAutoConfiguration  // 启动加载配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) // 组件扫描
public @interface SpringBootApplication {
    // ....
}

这里着重看一下@EnableAutoConfiguration注解,

@AutoConfigurationPackage // 注册自动配置的包
@Import(AutoConfigurationImportSelector.class) // 通过SPI机制自动导入配置
public @interface EnableAutoConfiguration {
   // ....
}

AutoConfigurationImportSelector类是实现自动配置的核心,它主要是使用使用了SpringFactories机制实现自动配置,SpringFactories的核心逻辑是从classpath中读取到所有jar包中的配置文件META-IF/spring.factories,然后根据指定的key从配置文件中解析出对应的value值,加载的逻辑如下图:

SpringBoot配置自动加载机制_第4张图片

源码实现如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
      ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
   @Override
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!isEnabled(annotationMetadata)) {
         return NO_IMPORTS;
      }
       // 获取自动配置
      AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
       // 返回配置类的全限定名
      return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
   }
          
   protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
       if (!isEnabled(annotationMetadata)) {
           return EMPTY_ENTRY;
       }
       // 获取属性
       AnnotationAttributes attributes = getAttributes(annotationMetadata);
       // 获取META-INF/spring.factories中的配置
       List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
       // 去重
       configurations = removeDuplicates(configurations);
       // 去掉排除的配置
       Set<String> exclusions = getExclusions(annotationMetadata, attributes);
       checkExcludedClasses(configurations, exclusions);
       configurations.removeAll(exclusions);
       configurations = getConfigurationClassFilter().filter(configurations);
       // 触发自动配置导入相关的事件
       fireAutoConfigurationImportEvents(configurations, exclusions);
       return new AutoConfigurationEntry(configurations, exclusions);
    }
          
    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;
	}
}

自动配置加载举例

以mybatis-plus的自动配置加载为例,首先引入依赖


<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.4.1version>
dependency>

在该jar包中的META-IF/spring.factories中,自动配置的信息如下

# Auto Configure
org.springframework.boot.env.EnvironmentPostProcessor=\
  com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration

SpringBoot启动时会自动加载这些配置

你可能感兴趣的:(SpringBoot,spring,boot,java,spring)