一、简介
- Springboot 源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
- 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的 springboot 源码管中窥豹系列。
二、框架
咱们先把 springboot 源码的框架理解分明。
1、新建一个 springboot 我的项目
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyprojectApplication {public static void main(String[] args) {SpringApplication.run(MyprojectApplication.class, args);
}
}
2、剖析源码
相比于 spring 我的项目或者 springmvc 我的项目,springboot 的入口很好找,就在 main 外面的 run 办法,咱们进入 run 办法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] {primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}
通过 SpringApplication 的静态方法,新建了一个 SpringApplication 类,调用它的 run 办法,咱们先看 SpringApplication 的构造方法,再看 run 办法
public SpringApplication(Class<?>... primarySources) {this(null, primarySources);
}
@SuppressWarnings({"unchecked", "rawtypes"})
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();}
构造方法次要做了这几件事:
- 确定 web 类型:webApplicationType
- 加载 ApplicationContextInitializer
- 加载 ApplicationListener
- 确定 applicationcontext 的实现类
实现细节咱们先不探讨,接着看 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;
}
run 办法做了几件事:
- stopwatch 记录 springboot 启动耗时
- 不同阶段触发 spring 的 listen 事件
- 新建 applicationcontext 实现类
- 启动 spring:refreshContext(context)
- 启动实现加载 runner
最重要的就是 refreshContext 办法,延用的 springframe 的 fresh 办法
private void refreshContext(ConfigurableApplicationContext context) {refresh((ApplicationContext) context);
if (this.registerShutdownHook) {
try {context.registerShutdownHook();
}
catch (AccessControlException ex) {// Not allowed in some environments.}
}
}
AbstractApplicationContext 类的办法
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();}
catch (BeansException ex) {if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization -" +
"cancelling refresh attempt:" + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();}
}
}
先不用深究,看看就好,理解整体的框架,至此 springboot 我的项目的源码主框架就是这样了。
- 外围能力还是 spring 的 refresh 办法
- 通过 SpringApplication 封装起来提供更多的性能。
这期就这样,从下期开始,咱们带着问题去源码外面找实现。
欢送关注公众号:丰极,更多技术学习分享。