关于springboot的自动配置原理,是非常非常非常重要的知识点,应该牢记和熟悉其原理!!!!!!!!!!
如果学过SpringMVC,一定有被XML 配置统治的恐惧。这也就是为什么SpringMVC被称为配置地狱。但是,Spring Boot 项目,我们只需要添加相关依赖,无需配置,通过启动下面的 main
方法即可。
1 2 3 4 5 6 7 @SpringBootApplication public class DemoApplication { public static void main (String[] args) { SpringApplication.run(DemoApplication.class, args); } }
自动装配可以说是springboot的核心。springboot自动配置原理就是当spring容器启动时候,一些配置类、、bean对象就自动存入IOC容器中,不需要我们手动申明,从而简化了开发,省去了繁琐的配置操作。
SpringBoot是如何实现自动装配的?
每一个启动类上都有springboot的核心注解SpringBootApplication 。点进SpringBootApplication之后:
1 2 3 4 5 6 7 8 9 @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 {...}
@SpringBootApplication封装了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解
@SpringBootApplication是springboot中最重要的注解
·@SpringBootConfiguration:底层封装了@Configuration注解,用来声明配置类
·@EnableAutoConfiguration:springboot实现自动化配置的核心注解
·@ComponentScan:组件扫描
@EnableAutoConfiguration
是实现自动装配的重要注解,我们以这个注解入手
@EnableAutoConfiguration:实现自动装配的核心注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @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 引入了@Import,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector
类。
AutoConfigurationImportSelector:加载自动装配类
AutoConfigurationImportSelector
类的继承体系如下:
1 2 3 4 5 6 7 8 9 10 11 12 public class AutoConfigurationImportSelector implements DeferredImportSelector , BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {} public interface DeferredImportSelector extends ImportSelector {} public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
可以看出,AutoConfigurationImportSelector
类实现了 ImportSelector
接口,也就实现了这个接口中的 selectImports
方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中 。
1 2 3 4 5 6 7 8 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
其中getAutoConfigurationEntry()
方法,这个方法主要负责加载自动配置类的。它会获取所有有效的自动配置类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected AutoConfigurationEntry getAutoConfigurationEntry (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 = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry (configurations, exclusions); }
其中getCandidateConfigurations方法用于获得所有的配置类,点击这个方法之后可以看到:
1 2 3 4 5 6 7 8 9 protected List<String> getCandidateConfigurations (AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = new ArrayList <>( SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct." ); return configurations; }
通过调用loadFactoryNames:
1 2 3 4 5 6 7 8 9 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()); }
其中最终loadSpringFactories获取需要自动装配的所有 配置类,读取META-INF/spring.factories
然后对加载到的所有配置类进行过滤,因为很多自动配置类都有条件注解;当条件注解@ConditionalOnXXX
中的所有条件都满足,该类才会生效。
总结
通过@SpringBootApplication 引入**@EnableAutoConfiguration**(负责启动自动配置功能)
@EnableAutoConfiguration 引入**@Import** 加载AutoConfigurationImportSelector
类
Spring容器启动时:加载Ioc容器会解析Import注解
@Import导入了一个DeferredImportSelector (它会使SpringBoot自动配置类的顺序在最后,这样方便我们扩展和覆盖)
然后读取所有的**/META-INF/spring.factories**文件(SPI)
过滤出所有AutoConfigurtionClass 类型的类
最后通过**@ConditionXXX**排除无效的自动配置类