- 前言
- SpringBoot是一个脚手架,通常喜欢拿SpringBoot和Spring做比较,SpringBoot只是对于SSM框架开发时候的配置项做了一个默认配置,将开发中约定大于配置进行了实现,大大节约了开发时间写各种繁琐的配置文件环节,达到了开箱即用的便捷体验
- SpringBoot入口
// 源码入口就是 @SpringBootApplication注解 public class BootDemoApplication { public static void main(String[] args) { SpringApplication.run(BootDemoApplication.class, args); } }
- 查看@SpringBootApplication注解
// 自动装配原理的核心注解 excludeFilters = { (type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), ( type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) (public @interface SpringBootApplication {
- 查看@EnableAutoConfiguration注解
/** * 自动装配的时候使用的是@Import注解 * 作用是导入一个或者多个组件搭配@Configuration注解使用,交给spring容器管理 * 该注解有三种方式 * 1.@import:指定导入一个或者多个类 * 2.ImportSelector:定义一个类实现该接口,重写selectImports方法 * 3. * 扩展:@ImportResource:指定导入一个或者多个xml文件 */ AutoConfigurationImportSelector.class) (public @interface EnableAutoConfiguration {
- AutoConfigurationImportSelector类源码解析
// 重写来自于DeferredImportSelector.Group#process public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // 获取自动装配信息 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } } // 获取自动装配信息 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); // 经过condition注解过滤后的自动配置类 configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } // ① META-INF/spring.factories中读取所有的候选的自动配置类名称 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 通过SpringFactoriesLoader读取所有的候选的自动配置类名称 // ② 加载配置候选的类 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; } // ③ 加载配置候选的类 protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; } // 所以如果想要将一个外部(第三方)的类交给spring容器管理,可以把这个类配置添加到META-INF/spring.factories文件中。 // 例如自定义starter场景启动器
- 总结:SpringBoot的自动装配原理本质上就是读取项目中所有的META-INF/spring.factories的配置类信息
- @Import之 ImportSelector/ImportBeanDefinitionRegistrar扩展
// ImportSelector (重要!SpringBoot底层使用这种方式,但是又有区别) public class MyImportSelector implements ImportSelector { public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 返回值String[]中值依旧是要导入类的全限定名,注意,返回值可以是空数组但是不能为null return new String[]{"com.fun.bootdemo.custome.Demo1"}; } } /** * SpringBoot底层使用的是: * org.springframework.boot.autoconfigure.AutoConfigurationImportSelector * 该类实现的是DeferredImportSelector接口,该接口包含有额外功能: * gruop 该分组可以用来进行排序和过滤时同时DeferredImportSelector是优先级比较低的, * 需要等到其他bean注册完了。才注册该接口导入的bean。这个功能很好的结合了@Conditon等条件注解 * 实现了用户自定义配置覆盖默认配置 */ // ImportBeanDefinitionRegistrar public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 指定注册bean定义信息 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Demo3.class); // demo3 是beanName registry.registerBeanDefinition("demo3", rootBeanDefinition); } } // 测试 (在配置类上) MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) ({