Bootstrap

spring starter原理和实例

spring starter原理和实例

背景

springboot的一个优势就是starter,利用starter,可以避免一些的繁琐的配置,将starter里面的功能开箱即用。例如:spring-boot-starter-jpa等,只需要配置一下数据连接信息,就可以进行数据库操作。当然starter技术也没有想象的高大上,最终也是一行行代码实现的,目前就让我们一起看一下接下面纱的starter。

spring starter实现原理

在META-INF/spring.factories文件中通过配置的key=value1,value2,…的方式,配置starter中自动配置的类,然后在springboot启动的时候,解析jar中的META-INF/spring.factories文件,将其通过一定的规则加载到当前的线程,通过代码调试目前发现可以在META-INF/spring.factories中添加如下几种配置:
spring.factories支持配置类型
spring.factories中的类型
接下来一起看一下SpringBoot在启动的时候,将spring.factories配置加载到进程中的步骤:
创建SpringBoot程序,默认在启动类中生成一个入口函数:

public static void main(String[] args) { 
SpringApplication.run(AutoconfigDemoApplication.class, args);
}

从在个主函数跟着代码进去,可以看见在SpringAppplication中具体实现,就是创建一个SpringApplication实例,然后运行run方法,starter加载机制也就是在这个过程中实现的。

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

接下来看一下SpringApplication的创建过程:通过getSpringFactoriesInstances方法读取spring.factories中ApplicationContextInitializer,ApplicationListener配置项。
创建SpringApplication
看一下getSpringFactoriesInstances读取spring.facotpries的细节见下图
spring.factories读取的细节
接下来看一下run方法
run方法
前面的代码不用分析,主要是准备对象,我们从 SpringApplicationRunListeners listeners = getRunListeners(args)开始分析,
第一步:是从类路径下META-INF/spring.factories获取SpringApplicationRunListeners,
这个方法跟前面分析的两个获取配置方法类似。
第二步:回调所有的获取SpringApplicationRunListener.starting()方法。
第三步: 封装命令行参数。
第四步:准备环境,调用prepareEnvironment方法。
第五步:打印Banner图(就是启动时的标识图)。
第六步:创建ApplicationContext,决定创建web的ioc还是普通的ioc。
第七步:异常分析报告。
第八步:准备上下文环境,将environment保存到ioc中
第九步:刷新容器,ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat),这个就是扫描,创建,加载所有组件的地方,(配置类,组件,自动配置)。
第十步:所有的SpringApplicationRunListener回调started方法。
第十一步:从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调,ApplicationRunner先回调,CommandLineRunner再回调。
第十二步:所有的SpringApplicationRunListener回调running方法。
第十三步:整个SpringBoot应用启动完成以后返回启动的ioc容器。
其中refreshContext(context)实际调用的AbstractApllicationContext#refresh(),也是在这个里面读取经常使用的EnableAutoConfiguration,refresh()#invokeBeanFactoryPostProcessors()方法中间会调用ConfigurationClassParser#processImports方法,获取到AutoConfigurationImportSelector,调用其selectImports
ConfigurationClassParser#processImports
utoConfigurationImportSelector#getCandidateConfigurations

自定义starter

自定义配置类需要用到的注解如下:

@ConditionalOnBean,仅在当前上下文中存在某个bean时,才会实例化这个Bean。

@ConditionalOnClass,某个class位于类路径上,才会实例化这个Bean。

@ConditionalOnExpression,当表达式为true的时候,才会实例化这个Bean。

@ConditionalOnMissingBean,仅在当前上下文中不存在某个bean时,才会实例化这个Bean。

@ConditionalOnMissingClass,某个class在类路径上不存在的时候,才会实例化这个Bean。

@ConditionalOnNotWebApplication,不是web应用时才会实例化这个Bean。

@AutoConfigureAfter,在某个bean完成自动配置后实例化这个bean。

@AutoConfigureBefore,在某个bean完成自动配置前实例化这个bean

步骤1:创建module,pom.xml需要调整一下:
spring-boot-configuration-processor
spring-boot-configuration-processor 的作用是编译时生成 spring-configuration-metadata.json ,在IDE中编辑配置文件时,会出现提示。
另外打包选择jar-no-fork,因为这里不需要main函数。
build
步骤2:EnableDemoConfiguration
不是必须的,建议有这样一个注释,作为自动配置启动的入口。
EnableDemoConfiguration
步骤3:DemoProperties
name和age对应application.properties里面的demo.name和demo.age
DemoProperties
步骤4:DemoAutoConfiguration
这里设置自动配置的相关条件,和相关操作,由于这里只想写一个最简单的demo,所以这里只需要简单注入一个bean,没有复杂逻辑,实际开发中,这个类是最关键的。
DemoAutoConfiguration
步骤5:DemoService
这里不需要@Service,因为已经通过DemoAutoConfiguration注入spring容器。
DemoService
步骤6:spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.johar.joharspringstarterautoconfig.DemoAutoConfiguration

步骤7:本地mvn install之后,在新的spring-boot项目里面引入自定义的jar,然后在启动类中开启配置。
AutoconfigDemoApplication
在配置文件application.properties中配置demo.age和demo.name
在配置文件
启动main函数,控制台会打印出配置文件中的name和age,自定义的spring-boot-starter就完成了。
输出

;