带着问题看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;}}}
到这里就差不多加载到配置文件了。