一、简介

  • Springboot源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
  • 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的springboot源码管中窥豹系列。

二、框架

咱们先把springboot源码的框架理解分明。

1、新建一个springboot我的项目

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic 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封装起来提供更多的性能。

这期就这样,从下期开始,咱们带着问题去源码外面找实现。

欢送关注公众号:丰极,更多技术学习分享。