目录
1、什么是自动配置
springboot自动配置是指在springboot应用启动时,可以把一些配置类自动注入到spring的ioc容器中,项目运行时可以直接使用这些配置类的属性。
2、为什么要使用自动配置
基于“约定优于配置”的理念,大多数配置使用默认的值即可满足要求,只需少量的自定义配置或者无需配置就可以使项目运行起来,使用自动配置可以使我们从繁重的spring配置中解放出来。
springboot有一个全局配置文件,application.properties或application.yml,各种属性都可以在文件中进行自定义配置,究竟哪些属性可以配置,不配置时默认值是多少,可以参考springboot的官方文档:Spring Boot Reference Documentation,里面对每个配置都有详细的介绍。
3、自动配置实现原理
用过springboot的人都知道,springboot启动类上有一个@SpringBootApplication注解,这是springboot项目一个必不可少的注解。
@SpringBootApplication public class AutoconfigApplication { public static void main(String[] args) { SpringApplication.run(AutoconfigApplication.class, args); } }
@SpringBootApplication是一个复合注解,其中包含了@EnableAutoConfiguration注解,该注解的意思为开启自动配置。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication
下面我们看下@EnableAutoConfiguration注解如何开启自动配置,@EnableAutoConfiguration也是一个复合注解,关键部分在它导入的AutoConfigurationImportSelector类中。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration
在AutoConfigurationImportSelector类中有一个selectImports()方法,通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包,获取获取spring.factories中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的值(配置类名),然后把这些类导入到spring的ioc容器中。
(1)selectImports()方法
public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
(2)SpringFactoriesLoader.loadFactoryNames()方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoader == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
(3)spring-boot-autoconfigure-x.x.x.x.jar里的spring.factories文件
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,......
springboot项目启动时,SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。
每个自动配置类对应了一组配置属性,比如DataSourceAutoConfiguration自动配置类,有一个@EnableConfigurationProperties注解,它的参数是一个DataSourceProperties类,该注解的作用就是把DataSourceProperties类的实例加载到spring的ioc容器中,而DataSourceProperties类中的属性就是自动配置的属性。
@Configuration( proxyBeanMethods = false ) @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class}) @ConditionalOnMissingBean( type = {"io.r2dbc.spi.ConnectionFactory"} ) @AutoConfigureBefore({SqlInitializationAutoConfiguration.class}) @EnableConfigurationProperties({DataSourceProperties.class}) @Import({DataSourcePoolMetadataProvidersConfiguration.class, InitializationSpecificCredentialsDataSourceInitializationConfiguration.class, SharedCredentialsDataSourceInitializationConfiguration.class}) public class DataSourceAutoConfiguration
DataSourceProperties类,有一个@ConfigurationProperties注解,它的作用就是把全局配置application.properties或者application.yml文件中以prefix开头的一组配置绑定到DataSourceProperties实例的属性上,实现自动配置。
@ConfigurationProperties( prefix = "spring.datasource" ) public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private ClassLoader classLoader; private boolean generateUniqueName = true; private String name; private Class<? extends DataSource> type; private String driverClassName; private String url; private String username; private String password; private String jndiName; ......
最后总结一下自动配置的流程:springboot启动时,会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,XxxxAutoConfiguration加载的时候会将全局配置application.properties或application.yml中的配置绑定到XxxxProperties类中(没有配置的属性将使用默认配置),注入到spring的ioc容器中。
4、动手实现一个自动配置类
1、编写一个与配置类,这个配置类使用@ConfigurationProperties注解与全局配置文件中的以myconfig开头的一组配置文件绑定。
@Data @Slf4j @ConfigurationProperties(prefix = "myconfig") public class ServiceProperties { private String name; public void print(){ log.info("自动配置成功。。。" + name); } }
2、编写一个自动配置加载类,这个类将使用@EnableConfigurationProperties注解将配置类加载到spring的ioc容器中。
@Configuration @EnableConfigurationProperties(ServiceProperties.class) public class SeviceAutoConfiguration { }
3、将编写的自动配置类添加到resources/META-INF/spring.factories(没有就新建一个)中EnableAutoConfiguration的值中。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ilan.autoconfig.config.SeviceAutoConfiguration
4、application.properties配置文件配置一个对应属性。
server.port=8080 myconfig.name=pengyulong
5、编写一个测试类,测试属性是否生效。
@RestController public class ControllerDemo { @Resource private ServiceProperties serviceProperties; @RequestMapping("test") public void test(){ serviceProperties.print(); } }
日志:2022-02-21 22:15:36.419 INFO 63382 --- [nio-8081-exec-1] c.i.a.service.ServiceProperties : 自动配置成功。。。pengyulong