SpringBoot
2021-04-18 20:18:08 0 举报
AI智能生成
SpingBoot在启动时候坐了哪些事情:两条路:注解和Run方法
作者其他创作
大纲/内容
线路一:@SpringBootApplication
@SpringBootConfiguration 配置类
@Configuration
public @interface SpringBootConfiguration{}
public @interface SpringBootConfiguration{}
SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类
@EnableAutoConfiguration 开启自动配置功能
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage 作用是将添加该注解的类所在的packpage作为自动配置进行管理(要扫描哪些包)
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
public @interface AutoConfigurationPackage {}
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
@Import(AutoConfigurationPackages.Registrar.class) 自动配置导入选择器
AutoConfigurationImportSelector自动配置导入选择器,那么它会导入哪些组件的选择器呢?
点进去看会发现有这样一个方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {}
99:getAutoConfigurationEntry //获取自动配置类
123:getCandidateConfigurations //获取候选配置
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader()); //获取配置,什么配置?:META-INF/spring.factories(这里在断言中就可以看到)
getBeanClassLoader()); //获取配置,什么配置?:META-INF/spring.factories(这里在断言中就可以看到)
假如没有断言呢?继续向下跟踪
loadFactoryNames方法(使用给定的类加载器从“ META-INF / spring.factories”加载给定类型的工厂实现的标准类名)
loadSpringFactories
OK,我们现在知道SpringBoot的自动配置是哪里来的了,下面我们返回Run方法,请回到开头←
@ComponentScan自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
路线二:Run方法追踪
public static void main(String[] args) {
SpringApplication.run(SpringBoot1Application.class, args);
}
SpringApplication.run(SpringBoot1Application.class, args);
}
这里可以总结为两步
1、一直深入不是run方法为止
public ConfigurableApplicationContext run(String... args)
prepareEnvironment(listeners, bootstrapContext, applicationArguments)
printBanner(environment);
createApplicationContext();
refreshContext(context);
refresh((ApplicationContext) context);
refreshContext(context)
applicationContext.refresh();
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
// context设置 启动日期/当前状态/初始环境/验证
this.prepareRefresh();
// 创建一个bean工程,
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
// 注册scope
this.postProcessBeanFactory(beanFactory);
// 调用所有bean工厂,对bean进行处理
this.invokeBeanFactoryPostProcessors(beanFactory);
// 拦截bean,
this.registerBeanPostProcessors(beanFactory);
// 国际化操作
this.initMessageSource();
// 广播事件
this.initApplicationEventMulticaster();
// 特殊bean 比如tomcat
this.onRefresh();
// 注册监听器
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
}
synchronized(this.startupShutdownMonitor) {
// context设置 启动日期/当前状态/初始环境/验证
this.prepareRefresh();
// 创建一个bean工程,
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
// 注册scope
this.postProcessBeanFactory(beanFactory);
// 调用所有bean工厂,对bean进行处理
this.invokeBeanFactoryPostProcessors(beanFactory);
// 拦截bean,
this.registerBeanPostProcessors(beanFactory);
// 国际化操作
this.initMessageSource();
// 广播事件
this.initApplicationEventMulticaster();
// 特殊bean 比如tomcat
this.onRefresh();
// 注册监听器
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
}
super.refresh();
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
继续跟进方法:invokeBeanFactoryPostProcessors
postProcessBeanDefinitionRegistry
processConfigBeanDefinitions(registry);
331:parser.parse(candidates);//解析候选配置
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}//谁便选一条即可
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}//谁便选一条即可
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
processConfigurationClass
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
递归处理配置类及其超类层次结构
点进去这个类你会发现注解的处理是在这里进行的
我们现在只关心线路一中的public String[] selectImports(AnnotationMetadata annotationMetadata) {}是哪里调用的
我们知道,在主启动类上的import注解里面会加载配置类,那么谁来调用加载呢?
找到310行,对于@Import注解的处理
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
581:String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
是不是又回到了最初的起点?
registerBeanPostProcessors(beanFactory);
registerListeners();
public ConfigurableApplicationContext run(String... args) {
// 创建计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 设置属性
this.configureHeadlessProperty();
// spring中监听器的使用,这些对象想创建,就得知道监听器的全路径
// 会从spring.factory中读取
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
// 初始化默认应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 根据监听器和默认的参数 来准备spring所需要的环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 打印出banner
Banner printedBanner = this.printBanner(environment);
// 创建应用上下文
context = this.createApplicationContext();
// 异常报告
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 准备应用上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
this.refreshContext(context);
// 刷新
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
// 执行callRunners, 支持自定义run方法
this.callRunners(context, applicationArguments);
}
// 创建计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 设置属性
this.configureHeadlessProperty();
// spring中监听器的使用,这些对象想创建,就得知道监听器的全路径
// 会从spring.factory中读取
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
// 初始化默认应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 根据监听器和默认的参数 来准备spring所需要的环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
// 打印出banner
Banner printedBanner = this.printBanner(environment);
// 创建应用上下文
context = this.createApplicationContext();
// 异常报告
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 准备应用上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
this.refreshContext(context);
// 刷新
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
// 执行callRunners, 支持自定义run方法
this.callRunners(context, applicationArguments);
}
2、通过构造方法加载初始化
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置一些资源加载器
this.resourceLoader = resourceLoader;
// 加载类资源不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
// 做一个数据结构的转换
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断当前项目类型是什么(判断该应用是否为WEB应用)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从Spring工厂获取Bootstrap注册表初始化程序
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//加载所有可用初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置说有可用监听程序监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 根据class 推断应用的入口类 通过run方法调用main方法
this.mainApplicationClass = deduceMainApplicationClass();
}
// 设置一些资源加载器
this.resourceLoader = resourceLoader;
// 加载类资源不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
// 做一个数据结构的转换
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断当前项目类型是什么(判断该应用是否为WEB应用)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从Spring工厂获取Bootstrap注册表初始化程序
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//加载所有可用初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置说有可用监听程序监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 根据class 推断应用的入口类 通过run方法调用main方法
this.mainApplicationClass = deduceMainApplicationClass();
}
WebApplicationType.deduceFromClasspath();
判断了我们的工程到底是个什么类型(web工程,基本的spring工程等)
getSpringFactoriesInstances(ApplicationContextInitializer.class));
getSpringFactoriesInstances(type, new Class<?>[] {});
SpringFactoriesLoader.loadFactoryNames(type, classLoader)
loadSpringFactories(classLoaderToUse)
通过类加载器获取META-INF/spring.factories文件生成并返回实例工厂
Pom文件
为什么有些启动器和依赖不用写版本号?
点进去看看
再点进去看看,你会发现,里面存有大量的版本管理
收藏
0 条评论
下一页