SpringBoot 项目间接继承 spring-boot-dependencies,该文件对常用技术框架进行了统一版本管理,所以在SpringBoot 项目 pom.xml 引入spring-boot-dependencies管理的依赖文件不需要标注依赖文件版本号。引入 starter 就可以实现对应场景开发,而不需要额外导入相关依赖文件。
SpringBoot 应用启动入口是@SpringBootApplication?注解标注类中的?main()?方法,@SpringBootApplication?能够扫描 Spring 组件并自动配置 SpringBoot
1 | @Target(ElementType.TYPE) |
@SpringBootConfiguration注解表示 Spring Boot 配置类,该注解仅仅是对@Configuration?注解的简单封装,与@Configuration?注解作用相同。
@EnableAutoConfiguration?注解表示开启自动配置功能。
1 | @Target(ElementType.TYPE) |
@AutoConfigurationPackage?注解
1 | @Target(ElementType.TYPE) |
1 | static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { |
@Import(AutoConfigurationImportSelector.class)
将?AutoConfigurationImportSelector?这个类导入到 Spring 容器中,?AutoConfigurationImportSelector?可以帮助 SpringBoot 应用将所有符合条件的配置都加载到当前 SpringBoot 创建并使用的 IoC 容器(ApplicationContext) 中。
通过源码分析这个类中是通过?selectImports()?这个方法告诉 SpringBoot 都需要导入哪些组件
1 | // 这个方法告诉springboot都需要导入那些组件 |
loadMetadata()
1 | final class AutoConfigurationMetadataLoader { |
getAutoConfigurationEntry()
1 | protected AutoConfigurationEntry getAutoConfigurationEntry( AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { |
getCandidateConfigurations()
1 | protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { |
loadFactoryNames()
1 | public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { |
@EnableAutoConfiguration?就是从classpath 中搜寻?MATE-INF/spring.factories?配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration?对应的配置项通过反射示例化为对应的标注了@Configuration?的JavaConfig形式的配置类,并加载到 IoC 容器中。
总结:
Springboot 底层实现自动装配的步骤是:
@ComponentScan?注解具体扫描的包的根路径由 Spring Boot 项目主程序启动类所在包的位置决定,在扫描过程中由前面介绍的?@AutoConfigurationPackage?注解进行解析,从而得到 Springboot 项目主程序启动类所在包的具体位置。
总结:
1 | |- @SpringBootConfiguration |
Starter 使得使用某个功能的开发者不需要关注各种依赖库的处理,不需要具体的配置信息,由Springboot 自动通过classpath 路径下的类发现需要的 bean,并织入相应的 Bean。
自建工程,命名为xxx-spring-boot-starter,导入spring-boot-autoconfigure依赖
编写配置类
resources 下创建?/META-INF/spring.factories,在该文件中配置自定义配置类
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\ com.test.config.MyAutoConfiguration |
测试使用
源代码
1 | //调用静态类,参数对应的就是SpringbootDemoApplication.class以及main方法中的args public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { ? ? return run(new Class<?>[] { primarySource }, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { ? ? //SpringApplication的启动由两部分组成: ? ? //1. 实例化SpringApplication对象 ? ? //2. run(args):调用run方法 ? ? return new SpringApplication(primarySources).run(args); } |
1 | public SpringApplication(Class<?>... primarySources) { ? ? this(null, primarySources); } @SuppressWarnings({ "unchecked", "rawtypes" }) public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { ? ? this.sources = new LinkedHashSet(); ? ? // Banner 模式 ? ? this.bannerMode = Mode.CONSOLE; ? ? this.logStartupInfo = true; ? ? // 是否添加 JVM 启动参数 ? ? this.addCommandLineProperties = true; ? ? this.addConversionService = true; ? ? this.headless = true; ? ? this.registerShutdownHook = true; ? ? this.additionalProfiles = new HashSet(); ? ? this.isCustomEnvironment = false; ? ? // 资源加载器 ? ? this.resourceLoader = resourceLoader; ? ? Assert.notNull(primarySources, "PrimarySources must not be null"); ? ? //项目启动类 SpringbootDemoApplication.class设置为属性存储起来 ? ? this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); ? ? //设置应用类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用) ? ? // deduceFromClasspath()方法用于查看 ClassPath类路径下是否存在某个特征类,从而判断webApplicationType ? ? this.webApplicationType = WebApplicationType.deduceFromClasspath(); ? ? // 设置初始化器(Initializer),最后会调用这些初始化器 ? ? //所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,在Spring上下文被刷新之前进行初始化的操作 ? ? setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); ? ? // 设置监听器(Listener) ? ? setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); ? ? // 初始化 mainApplicationClass 属性:用于推断并设置项目main()方法启动的主程序启动类 ? ? this.mainApplicationClass = deduceMainApplicationClass(); } |
1 | public ConfigurableApplicationContext run(String... args) { |