依赖管理
spring-boot-starter-parent如何管理依赖版本
每一个springboot项目都有一个依赖管理
点版本号查看,发现底层有一个父依赖spring-boot-dependencies,然后继续点击spring-boot-dependencies查看源码,发下如下
项目运行依赖的jar包的管理
例如,如果你想给springboot添加web功能,只需引入spring-boot-starter-web
那么,springboot又是如何做到只引入一个依赖就能集成所有的依赖,我们进入spring-boot-starter-web查看源码,
自动装配
概念
如何进行自动装配,哪些组件进行了自动装配
先查看Springboot的启动类
核心注解@SpringBootApplication底层源码如下
@SpringBootConfiguration
@EnableAutoConfiguration
下边,我们分别来看这两个注解
@AutoConfigurationPackage
通过Debug模式可以看到,在Registrar类中的registerBeanDefinitions方法中调用register方法(此方法属于AutoConfigurationPackages),传入的实参
new PackageImports(metadata).getPackageNames().toArray(new String[0])的值为com.mycode.springbootdemo,也就是说,@AutoConfigurationPackage注解的主要作用就是将启动类所在的包以及子包下的所有组件扫描进I
@Import(AutoConfigurationImportSelector.class)
我们先看AutoConfigurationImportSelector这个类源码,里边有个方法selectImports告诉springboot都需要导入哪些组件
通过点击getAutoConfigurationEntry方法里边的getCandidateConfigurations方法
getCandidateConfigurations方法里边有一个重要的方法loadFactoryNames,这个方法是让SpringFactoryLoader去加载一些组件名称
继续点开loadFactoryNames,点开里边的重载方法loadSpringFactories,可以看到会去读取一个spring.factories文件FACTORIES_RESOURCE_LOCATION
继续查看文件,可以看到
这个是去加载外部文件,而这个文件是在
@ComponentScan
总结
执行原理
springapplication实例的初始化创建
查看springapplication实例化的核心代码,如下
1 this.webApplicationType = WebApplicationType.deduceFromClasspath();
2 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
3 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
4 this.mainApplicationClass = deduceMainApplicationClass();
项目的初始化启动
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
从源码中可以看出,项目初始化启动大致可以分为以下几类
第一步:获取并启动监听器
getRunListeners(args)和starting主要用户获取SpringApplication实例化过程中初始化的SpringApplicationRunListener并且运行
第二步:根据SpringApplicationRunListeners以及参数来准备环境
prepareEnvironment(listeners, applicationArguments)方法主要对项目运行环境进行预设值;同时通过configureIgnoreBeanInfo(environment)方法排除掉一些不需要的运行环境
第三步:创建spring容器
context = createApplicationContext();
第四步:spring容器前置处理
prepareContext(context, environment, listeners, applicationArguments, printedBanner) 这一步主要是容器刷新之前的准备动作,设置容器环境,包括各种变量等等,其中包含一步非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础
第五步:刷新容器
refreshContext(context);
第六步:spring容器后置处理
afterRefresh(context, applicationArguments);
第七步:发出结束执行的事件
listeners.started(context);
第八步:执行Runners
第九步:发布应用上下文就绪事件
listeners.running(context);
如果在前面的一切初始化启动都没有问题,使用运行监听器SpringApplicationRunListener持续运行配置好的应用上线文applicationcontext