在Spring Boot 中咱们想要使用某个功能只须要在POM文件中添加对应的依赖。而后整个应用程序便具有了这个功能。那么这是如何实现的呢?html
经过分析Spring Boot 示例程序来分析Spring Boot 自动配置原理。java
Spring Boot 应用启动的时候,须要传入一个标注@SpringBootApplication
注解,该注解是一个组合注解。spring
@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 { //省略 }
该注解是Spring Boot 对Spring 的@Configuration注解的一个包装,它的做用就是表名被标注的类是一个配置类!这里就不在过多描述,须要了解能够经过查看官方文档。springboot
该注解开启了自动配置功能,它也是一个组合注解。app
@AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@AutoConfigurationPackage注解 配和 @ComponentScan 来决定Spring Boot 从那个包开始扫描组件,有怎样的扫描规则等等。 咱们如今主要关心@Import(EnableAutoConfigurationImportSelector.class)
给应用带来了什么ide
@Import
注解的做用,已经在给IOC容器添加组件的几种方式总结 作过介绍分析。 直接点击EnableAutoConfigurationImportSelector
观察,该类继承了AutoConfigurationImportSelector
,关注这个类的selectImports
方法spring-boot
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } try { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); AnnotationAttributes attributes = getAttributes(annotationMetadata); //获取全部的候选配置信息 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); configurations = sort(configurations, autoConfigurationMetadata); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return configurations.toArray(new String[configurations.size()]); } catch (IOException ex) { throw new IllegalStateException(ex); } }
观察getCandidateConfigurations
方法this
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); return configurations; }
观察getSpringFactoriesLoaderFactoryClass
方法,该方法返回了EnableAutoConfiguration
的类类型url
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
返回到getCandidateConfigurations
这个方法,观察loadFactoryNames
方法.net
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { //获取EnableAutoConfiguration全限定名称 String factoryClassName = factoryClass.getName(); try { //加载 类路径下 META-INF文件夹中的spring.factories文件 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List<String> result = new ArrayList<String>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); //将spring.factories文件转为Properties文件 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); //读取key为EnableAutoConfiguration全限定名称对应的全部值 String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { } }
这个常量FACTORIES_RESOURCE_LOCATION的值为:META-INF/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,\ org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\ org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\ org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\ ## 省略
再返回到selectImports
方法。实际上就是将这个配置文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration
对应的值,按照必定的过滤规则,最后把他们交给了容器。 每个这样的xxxAutoConfiguration类都是容器中的一个组件,而且它们都是一个配置类,当这些组件交给Spring容器管理,也就使得应用程序完成了自动配置。
分析完上述内容,就能够自定义一个应用场景启动器。具体步骤以下
spring.factories
文件。org.springframework.boot.autoconfigure.EnableAutoConfiguration
=自定义配置类的全限定名称