SpringBoot启动
springBoot启动全流程如下所示:
BeanFactoryPostProcessor和BeanPostProcessor都是Spring框架中的接口,它们在bean的生命周期中扮演着不同的角色。
BeanFactoryPostProcessor:这是一个更早的处理器,它可以在所有的bean定义被加载到bean工厂,但是bean实例化之前进行一些定制的处理。这个接口只有一个方法:postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException。
BeanPostProcessor:这是一个更晚的处理器,它是在bean实例化之后,在执行bean的初始化方法前后,可以对bean进行一些定制的处理。这个接口有三个方法:
postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
postProcessAfterInitialization(Object bean, String beanName) throws BeansException
简单来说,BeanFactoryPostProcessor是在bean定义加载阶段进行处理,而BeanPostProcessor则是在bean实例化后进行处理。
框架初始化,完成相关配置:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
执行run方法:
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;
}
springBoot环境准备:
1 Devtools全局配置 2 测试环境@TestPropertySource注解 3 测试环境properties属性 4 命令行参数 5 SPRING_APPLICATION_JSON属性 6 ServletConfig初始化参数 7 ServletContext初始化参数 8JNDI属性 9 JAVA系统属性 10 操作系统环境变量 11 RandomValuePropertySource随机值属性 12 jar包外的application-{profile}.properties 13 jar包内的application-{profile}.properties 14 jar包外的application.properties 15 14 jar包内的application.properties 16 @PropertySource绑定配置 17 默认属性
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()) .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
环境准备流程图解析:
准备上下文:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
//遍历调用Initializer的Initilize方法
applyInitializers(context);
//发送ApplicationContextInitializedEvent事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册springApplicationArguments
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//springBootBanner
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//加载sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//发送ApplicationPreparedEvent事件
listeners.contextLoaded(context);
}
刷新上下文
obtainFreshBeanFactory方法内部通过调用loadBeanDefinitions方法完成了bean定义的加载。
PrepareBeanFactory内部配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器postProcessors.
postProcessBeanFactory方法允许在bean没有实例化前允许修改应用上下文的内部beanFactory, 允许注册特殊的beanPostProcessors
invokeBeanFactoryPostProcessors方法实例化并调用所有注册的BeanFactoryPostProcessor bean, 并完成对于由@Configration注解的配置类的加载。
finishBeanFactoryInitialization方法实例化所有非惰性加载单例bean, 通过defaultListableBeanFactory的preInstantiateSingletons实例化单例bean,具体创建由abstractBeanFactory的getBean方法完成,从这里开始就和spring实例化bean有些类似了。
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
//所属类:ApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备刷新此上下文。
prepareRefresh();
//告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备bean工厂以便在此上下文中使用。
prepareBeanFactory(beanFactory);
try {
//允许在上下文子类中对bean工厂进行后处理。
//在标准初始化之后修改应用程序上下文的内部bean工厂。
//所有的bean定义都将被加载,但还没有任何bean被实例化。这允许在某些ApplicationContext实现中注册特殊的BeanPostProcessors
postProcessBeanFactory(beanFactory);
//调用在上下文中注册为bean的工厂处理器(beanFactoryPostProcessor)
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
//初始化此上下文的消息源。
initMessageSource();
//初始化此上下文的事件多播。
initApplicationEventMulticaster();
//初始化特定上下文子类中的其他特殊bean。
onRefresh();
//检查侦听器bean并注册它们。
registerListeners();
//实例化所有剩余的(非惰性init)singleton。
finishBeanFactoryInitialization(beanFactory);
//最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
//销毁已创建的singleton以避免挂起资源。
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
//重置Spring核心中的常见内省缓存,因为我们可能再也不需要单例bean的元数据了。。。
resetCommonCaches();
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)