带着问题看SpringBoot
1、Spring容器具体是什么?
跟进run方法,context = this.createApplicationContext(),得出容器是AnnotationConfigServletWebServerApplicationContext类。
SpringApplication.run(ServeroneApplication.class, args);
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
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);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
2、SpringBoot中Tomcat的启动流程。
2.1、跟进TomcatWebServer类的initialize() 方法,断点到logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));然后反向debug你可以看出Tomcat的初始化过程,是在容器执行run()方法的时候执行refresh()方法的this.onRefresh();的时候初始化的。
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
synchronized(this.monitor) {
try {
this.addInstanceIdToEngineName();
Context context = this.findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && "start".equals(event.getType())) {
this.removeServiceConnectors();
}
});
this.tomcat.start();
this.rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
} catch (NamingException var5) {
}
this.startDaemonAwaitThread();
} catch (Exception var6) {
this.stopSilently();
this.destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", var6);
}
}
}
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
//Tomcat初始化
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
3、SpringBoot加载配置文件。
3.1、跟进run()到SpringApplication类的run()方法的ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
SpringApplication.run(TestApplication.class, args);
3.2、跟进prepareEnvironment()—>listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);—>SimpleApplicationEventMulticaster类的doInvokeListener()方法。
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
String msg = var6.getMessage();
if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
throw var6;
}
Log logger = LogFactory.getLog(this.getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, var6);
}
}
}
当listener为EnvironmentPostProcessorApplicationListener的时候,进入onApplicationEvent()方法。
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
}
if (event instanceof ApplicationPreparedEvent) {
this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
}
if (event instanceof ApplicationFailedEvent) {
this.onApplicationFailedEvent((ApplicationFailedEvent)event);
}
}
跟进onApplicationEnvironmentPreparedEvent()方法。
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
Iterator var4 = this.getEnvironmentPostProcessors(event.getBootstrapContext()).iterator();
while(var4.hasNext()) {
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();
postProcessor.postProcessEnvironment(environment, application);
}
}
跟进到ConfigDataEnvironmentPostProcessor类的postProcessEnvironment()。
void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles) {
try {
this.logger.trace("Post-processing environment to add config data");
ResourceLoader resourceLoader = resourceLoader != null ? resourceLoader : new DefaultResourceLoader();
this.getConfigDataEnvironment(environment, (ResourceLoader)resourceLoader, additionalProfiles).processAndApply();
} catch (UseLegacyConfigProcessingException var5) {
this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]", var5.getConfigurationProperty()));
this.postProcessUsingLegacyApplicationListener(environment, resourceLoader);
}
}
跟进processAndApply()方法。
void processAndApply() {
ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers, this.loaders);
this.bootstrapContext.register(Binder.class, InstanceSupplier.from(() -> {
return this.contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});
}));
ConfigDataEnvironmentContributors contributors = this.processInitial(this.contributors, importer);
Binder initialBinder = contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});
this.bootstrapContext.register(Binder.class, InstanceSupplier.of(initialBinder));
ConfigDataActivationContext activationContext = this.createActivationContext(initialBinder);
contributors = this.processWithoutProfiles(contributors, importer, activationContext);
activationContext = this.withProfiles(contributors, activationContext);
contributors = this.processWithProfiles(contributors, importer, activationContext);
this.applyToEnvironment(contributors, activationContext);
}
跟进this.processInitial(this.contributors, importer)方法->withProcessedImports()方法->importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports)方法->this.load(loaderContext, resolved);
ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
ConfigDataEnvironmentContributor.ImportPhase importPhase = ImportPhase.get(activationContext);
this.logger.trace(LogMessage.format("Processing imports for phase %s. %s", importPhase, activationContext != null ? activationContext : "no activation context"));
ConfigDataEnvironmentContributors result = this;
int processed = 0;
while(true) {
ConfigDataEnvironmentContributor contributor = this.getNextToProcess(result, activationContext, importPhase);
if (contributor == null) {
this.logger.trace(LogMessage.format("Processed imports for of %d contributors", processed));
return result;
}
if (contributor.getKind() == Kind.UNBOUND_IMPORT) {
Iterable<ConfigurationPropertySource> sources = Collections.singleton(contributor.getConfigurationPropertySource());
PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(result, activationContext, true);
Binder binder = new Binder(sources, placeholdersResolver, (ConversionService)null, (Consumer)null, (BindHandler)null);
ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(binder);
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, bound));
} else {
ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(result, contributor, activationContext);
ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
List<ConfigDataLocation> imports = contributor.getImports();
this.logger.trace(LogMessage.format("Processing imports %s", imports));
Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports);
this.logger.trace(LogMessage.of(() -> {
return this.getImportedMessage(imported.keySet());
}));
ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase, this.asContributors(imported));
result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, contributorAndChildren));
++processed;
}
}
}
到这里就差不多加载到配置文件了。