springboot内容总结
springboot源码学习过程记录
springboot 程序是通过 SpringApplication这个类来启动一个Java主程序
当前是基于springboot的2.6.13版本来学习的
调用SpringApplication的构造函数创建对象,然后调用run方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 当前应用程序的类型,返回SERVLET,有三种 SERVLET/ NONE/ REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这里做了很多事情
- 配置resourceLoader
- 存主类信息
- 判断当前应用程序的类型
- 加载Spring应用上下文初始化器,获取初始化器的实例对象(从spring.factory中拿到全限定类型,再通过反射做的)
- 加载监听器(ApplicationListener),设置监听器的实例对象(和上面一样,是加载了所有包下的spring.factory)
- 找到应用程序的主类,开始执行
然后执行run方法
执行run()方法,传args参数过去,之后是应用程序启动的整个过程
public ConfigurableApplicationContext run(String... args) {
// 程序启动时间
long startTime = System.nanoTime();
//
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 上下文环境,创建context对象
ConfigurableApplicationContext context = null;
// 没什么用,设置系统参数中java.awt.headless值为true
configureHeadlessProperty();
// 创建监听器对象
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听器
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 设置参数args,就是命令行参数,传参数是以--开头,即--key=value
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
获取监听器
从spring.facotries中获取到类EventPublishingRunListener,通过反射实例化后返回。是一个事件发布运行监听器,在Spring Boot 启动过程中发布各种事件,通过一个多路广播器,将springboot运行状态的变化构建成事件,并广播给各个监听器
SpringApplicationRunListeners封装了所有的启动监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
// 从spring.factories文件中,通过SpringApplicationRunListener这个key,获取到对于的监听器
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
启动监听器
在运行过程中监听某些事件,不同的监听器监听的事件是不一样的
SpringApplicationRunListeners.java
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
EventPublishingRunListener.java
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
创建环境配置的类,加一些环境参数,准备运行的环境
SpringApplication.java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 环境准备,EventPublishingRunListener.environmentPrepared方法,从spring.factories中拿到
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = convertEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
prepareContext方法
把启动类加载到上下文应用环境context里
refreshContext方法
实现自动化配置
springboot的自动装配过程
@SpringBootApplication 注解里有3个很重要的注解@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@SpringBootConfiguration注解:
表示这个类是一个配置类,它是@Configuration注解的派生注解,与@Configuration注解的功能一致。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@AutoConfigurationPackage 注解:将主程序类所在包及所有子包下的组件到扫描到spring容器中。
AutoConfigurationImportSelector 是一个选择器,有一个方法getCandidateConfigurations,从spring.factory加载EnableAutoConfiguration对应的自动配置类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}
}
在refresh()方法里,使用invokeBeanFactoryPostProcessors(beanFactory)方法,通过反射来实例化所有需要注册的BeanFactoryPostProcessor的bean,在这个方法处理过程中,
最终使用processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);方法解析配置类
即使用ConfigurationClassParser 解析@Configuration注解标识的类
调用org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass方法,查看有没有加@ComponentScan注解,有注解则扫描包下的类,就可以扫描到加注解需要注入的类,解析成BeanDefinitionHolder,放到set集合里。
然后处理所有的@Import注解,加载import注解的属性值

之后this.deferredImportSelectorHandler.process()方法去处理,通过grouping.getImports()去调用AutoConfigurationImportSelector类里的方法,得到spring.factory里的EnableAutoConfiguration对应的配置类,加载进来,并过滤掉不需要的
class ConfigurationClassParser {
@Nullable
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
}
springboot启动过程:
每个springboot应用程序都有一个主入口,是一个main方法,在方法里调用SpringApplication.run()方法来启动程序,这个类必须加@SpringBootApplication注解
初始化
1. 判断当前应用程序的类型
有3种,默认返回SERVLET
NONE
SERVLET
REACTIVE
2. 加载所有的初始化容器
3. 加载所有的监听器
4. 找到程序运行的主类
开始执行run方法
1. 记录程序启动时间,创建bootstrapContext 上下文环境
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
2. 配置系统属性 java.awt.headless
3. 创建应用的监听器SpringApplicationRunListeners并开始监听。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
4. 加载命令行的参数值
解析在命令行中(--key=value)输入的属性值,封装到AppplicationArguments对象中
new SimpleCommandLineArgsParser().parse(args)
5. 准备当前应用程序的环境
根据应用程序的类型SERVLET得到的
然后对象当前环境进行配置
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
调用listeners(EventPublishingRunListener)准备环境
listeners.environmentPrepared(bootstrapContext, environment);
6. 配置系统属性,是否忽略一些bean的加载
配置项为(true/false):
spring.beaninfo.ignore
configureIgnoreBeanInfo(environment);
7. 生成banner对象,准备打印
a. 先判断是否有图片,支持jpg、gif、png格式的图片
b. 读取banner.txt文件中内容
c. 循环打印输入默认的banner
8. 准备上下文应用对象,根据应用程序类型(webApplicationType)判断创建哪种上下文对象
createApplicationContext();
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
super.setApplicationStartup(applicationStartup);
this.beanFactory.setApplicationStartup(applicationStartup);
}
}
9. 设置ApplicationStartup到应用上下文context
context.setApplicationStartup(this.applicationStartup);
10.准备上下文对象ConfigurableApplicationContext
根据当前应用程序的类型来判断创建哪种格式的上下文对象
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
a. 初始化,想beanFactory中注入了三个postporcessor的对象,后续在字段装备的时候会用到
applyInitializers(context);
b. 执行监听器 listeners.contextPrepared(context);
c. 加载很多资源配置,完成自动装配
load(context, sources.toArray(new Object[0]));
d. listeners.contextLoaded(context);
11. 刷新上下文环境
12. refresh之后的扩展,默认是空的
afterRefresh(context, applicationArguments);
13. 计时,打印启动程序耗时多长时间
14. 运行所有的监听器对象
listeners.started(context, timeTakenToStartup);
BeanFactoryPostProcessor 和 BeanPostProcessor 的区别:
1. 作用阶段
-
BeanFactoryPostProcessor:
是修改beanDefination的,在bean实例化之前执行的。即:容器加载完bean定义信息,封装成beanDefination,BeanFactoryPostProcessor 的 postProcessBeanFactory 方法会在所有的 BeanDefinition 加载完成之后,且在 bean 实例化之前被调用。 -
BeanPostProcessor:
是修改bean的,在 Bean 实例化和 依赖注入完成后,以及 初始化方法调用前后执行。
2. 接口方法
-
BeanFactoryPostProcessor:
定义了方法 postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)。
该方法的参数是 BeanFactory,可以访问并修改 BeanDefinition。 -
BeanPostProcessor:
定义了两个方法:
postProcessBeforeInitialization(Object bean, String beanName):在 Bean 的初始化方法调用之前执行。
postProcessAfterInitialization(Object bean, String beanName):在 Bean 的初始化方法调用之后执行。

浙公网安备 33010602011771号