1. 程式人生 > >springboot原始碼解析之SpringApplication初始化、啟動

springboot原始碼解析之SpringApplication初始化、啟動

開發十年,就只剩下這套架構體系了! >>>   

說在前面

本次開始spring-boot原始碼解析,更多精彩原始碼解析文章請關注”天河聊架構“微信公眾號。

 

原始碼解析

建立SpringApplication物件進入到這個方法org.springframework.boot.SpringApplication#SpringApplication(java.lang.Object...)

public SpringApplication(Object... sources) {
   initialize(sources);
}

進入到這個方法org.springframework.boot.SpringApplication#initialize

private void initialize(Object[] sources) {
      if (sources != null && sources.length > 0) {
         this.sources.addAll(Arrays.asList(sources));
      }
      this.webEnvironment = deduceWebEnvironment();
//    載入初始化器
      setInitializers((Collection) getSpringFactoriesInstances(
            ApplicationContextInitializer.class));
//    載入監聽器
      setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
      this.mainApplicationClass = deduceMainApplicationClass();
   }

進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)從META-INF/spring.factories路徑載入ApplicationContextInitializer

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer

進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)從META-INF/spring.factories路徑載入

ApplicationListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener

進入到這個方法org.springframework.boot.SpringApplication#deduceMainApplicationClass

根據main方法找到應用啟動類

private Class<?> deduceMainApplicationClass() {
   try {
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
         if ("main".equals(stackTraceElement.getMethodName())) {
            return Class.forName(stackTraceElement.getClassName());
         }
      }
   }
   catch (ClassNotFoundException ex) {
      // Swallow and continue
   }
   return null;
}

進入到這個方法org.springframework.boot.SpringApplication#run(java.lang.String...)

//  spring-boot原始碼解析 應用啟動
   public ConfigurableApplicationContext run(String... args) {
      StopWatch stopWatch = new StopWatch();
      stopWatch.start();
      ConfigurableApplicationContext context = null;
      FailureAnalyzers analyzers = null;
      configureHeadlessProperty();
//    初始化SpringApplicationRunListener -》
      SpringApplicationRunListeners listeners = getRunListeners(args);
      listeners.starting();
      try {
         ApplicationArguments applicationArguments = new DefaultApplicationArguments(
               args);
         ConfigurableEnvironment environment = prepareEnvironment(listeners,
               applicationArguments);
//       列印banner
         Banner printedBanner = printBanner(environment);
//       初始化spring上下文 -》
         context = createApplicationContext();
         analyzers = new FailureAnalyzers(context);
//       準備spring上下文 -》
         prepareContext(context, environment, listeners, applicationArguments,
               printedBanner);
//       重新整理spring上下文 -》
         refreshContext(context);
//       spring上下文初始化完畢載入其他applicationRunner
         afterRefresh(context, applicationArguments);
//       執行監聽器spring載入完成事件
         listeners.finished(context, null);
         stopWatch.stop();
         if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                  .logStarted(getApplicationLog(), stopWatch);
         }
         return context;
      }
      catch (Throwable ex) {
         handleRunFailure(context, listeners, analyzers, ex);
         throw new IllegalStateException(ex);
      }
   }

進入到這個方法org.springframework.boot.SpringApplication#getRunListeners

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
         SpringApplicationRunListener.class, types, this, args));
}

進入到這個方法org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
         Class<?>[] parameterTypes, Object... args) {
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      // Use names and ensure unique to protect against duplicates
//    載入META-INF/spring.factories配置的SpringApplicationRunListener監聽器
      Set<String> names = new LinkedHashSet<String>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//    建立META-INF/spring.factories配置的SpringApplicationRunListener監聽器物件
      List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
      AnnotationAwareOrderComparator.sort(instances);
      return instances;
   }

進入到這個方法org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames,從META-INF/spring.factories路徑下載入監聽器

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
        ArrayList result = new ArrayList();
        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String propertyValue = properties.getProperty(factoryClassName);
            String[] var8 = StringUtils.commaDelimitedListToStringArray(propertyValue);
            int var9 = var8.length;
            for(int var10 = 0; var10 < var9; ++var10) {
                String factoryName = var8[var10];
                result.add(factoryName.trim());
            }
        }

        return result;
    } catch (IOException var12) {
        throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var12);
    }
}
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

返回到這個方法建立監聽器的例項org.springframework.boot.SpringApplication#createSpringFactoriesInstances

private <T> List<T> createSpringFactoriesInstances(Class<T> type,
      Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
      Set<String> names) {
   List<T> instances = new ArrayList<T>(names.size());
   for (String name : names) {
      try {
         Class<?> instanceClass = ClassUtils.forName(name, classLoader);
         Assert.isAssignable(type, instanceClass);
         Constructor<?> constructor = instanceClass
               .getDeclaredConstructor(parameterTypes);
         T instance = (T) BeanUtils.instantiateClass(constructor, args);
         instances.add(instance);
      }
      catch (Throwable ex) {
         throw new IllegalArgumentException(
               "Cannot instantiate " + type + " : " + name, ex);
      }
   }
   return instances;
}

進入到這個方法org.springframework.boot.context.event.EventPublishingRunListener#starting廣播應用啟動事件

@Override
@SuppressWarnings("deprecation")
public void starting() {
   this.initialMulticaster
         .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}

進入到這個方法org.springframework.boot.SpringApplication#createApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
      Class<?> contextClass = this.applicationContextClass;
      if (contextClass == null) {
         try {
//          建立基於annotation的上下文物件
            contextClass = Class.forName(this.webEnvironment
                  ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
         }
         catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                  "Unable create a default ApplicationContext, "
                        + "please specify an ApplicationContextClass",
                  ex);
         }
      }
      return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
   }

進入到這個方法org.springframework.boot.SpringApplication#prepareContext

private void prepareContext(ConfigurableApplicationContext context,
         ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
         ApplicationArguments applicationArguments, Banner printedBanner) {
      context.setEnvironment(environment);
      postProcessApplicationContext(context);
//    執行初始化器 =》
      applyInitializers(context);
//    執行監聽器上下文準備事件 -》
      listeners.contextPrepared(context);
      if (this.logStartupInfo) {
         logStartupInfo(context.getParent() == null);
         logStartupProfileInfo(context);
      }

      // Add boot specific singleton beans
      context.getBeanFactory().registerSingleton("springApplicationArguments",
            applicationArguments);
      if (printedBanner != null) {
         context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
      }

      // Load the sources
      Set<Object> sources = getSources();
      Assert.notEmpty(sources, "Sources must not be empty");
//    載入bean定義 =》
      load(context, sources.toArray(new Object[sources.size()]));
//    執行spring上線文載入完成事件 -》
      listeners.contextLoaded(context);
   }

進入這個方法org.springframework.boot.SpringApplication#postProcessApplicationContext,對applicationContext的後置處理

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
   if (this.beanNameGenerator != null) {
      context.getBeanFactory().registerSingleton(
            AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
   }
   if (this.resourceLoader != null) {
      if (context instanceof GenericApplicationContext) {
         ((GenericApplicationContext) context)
               .setResourceLoader(this.resourceLoader);
      }
      if (context instanceof DefaultResourceLoader) {
         ((DefaultResourceLoader) context)
               .setClassLoader(this.resourceLoader.getClassLoader());
      }
   }
}

返回到這個方法org.springframework.boot.SpringApplication#applyInitializers

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
            initializer.getClass(), ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
   }
}

進入這個方法org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#initialize

@Override
public void initialize(ConfigurableApplicationContext context) {
   context.addBeanFactoryPostProcessor(
         new ConfigurationWarningsPostProcessor(getChecks()));
}

進入這個方法org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer#getChecks

protected Check[] getChecks() {
   return new Check[] { new ComponentScanPackageCheck() };
}

找到這裡

static {
         Set<String> packages = new HashSet<String>();
//       預設會掃描org.springframework下所有的包
         packages.add("org.springframework");
         packages.add("org");
         PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);
      }

springboot啟動的時候元件掃描器會預設掃描這兩個包。

進入這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#getInitializerClasses

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
//    載入初始化類context.initializer.classes
      String classNames = env.getProperty(PROPERTY_NAME);
      List<Class<?>> classes = new ArrayList<Class<?>>();
      if (StringUtils.hasLength(classNames)) {
         for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
            classes.add(getInitializerClass(className));
         }
      }
      return classes;
   }

返回到這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializerClasses

private void applyInitializerClasses(ConfigurableApplicationContext context,
         List<Class<?>> initializerClasses) {
      Class<?> contextClass = context.getClass();
      List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>();
      for (Class<?> initializerClass : initializerClasses) {
//       初始化初始化器
         initializers.add(instantiateInitializer(contextClass, initializerClass));
      }
      applyInitializers(context, initializers);
   }

進入這個方法org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializers

private void applyInitializers(ConfigurableApplicationContext context,
         List<ApplicationContextInitializer<?>> initializers) {
      Collections.sort(initializers, new AnnotationAwareOrderComparator());
      for (ApplicationContextInitializer initializer : initializers) {
//       執行初始化器的初始化方法
         initializer.initialize(context);
      }
   }

返回到這個方法org.springframework.boot.SpringApplicationRunListeners#contextPrepared執行監聽器

public void contextPrepared(ConfigurableApplicationContext context) {
   for (SpringApplicationRunListener listener : this.listeners) {
      listener.contextPrepared(context);
   }
}

進入到這個方法org.springframework.boot.SpringApplication#load載入bean定義

protected void load(ApplicationContext context, Object[] sources) {
      if (logger.isDebugEnabled()) {
         logger.debug(
               "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
      }
//    建立bean定義載入器
      BeanDefinitionLoader loader = createBeanDefinitionLoader(
            getBeanDefinitionRegistry(context), sources);
      if (this.beanNameGenerator != null) {
//       設定beanName生成器
         loader.setBeanNameGenerator(this.beanNameGenerator);
      }
      if (this.resourceLoader != null) {
         loader.setResourceLoader(this.resourceLoader);
      }
      if (this.environment != null) {
         loader.setEnvironment(this.environment);
      }
//    載入bean定義 =》
      loader.load();
   }

進入到這個方法org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)

private int load(Object source) {
      Assert.notNull(source, "Source must not be null");
      if (source instanceof Class<?>) {
         return load((Class<?>) source);
      }
      if (source instanceof Resource) {
         return load((Resource) source);
      }
//    註解掃描器載入bean定義
      if (source instanceof Package) {
         return load((Package) source);
      }
      if (source instanceof CharSequence) {
         return load((CharSequence) source);
      }
      throw new IllegalArgumentException("Invalid source type " + source.getClass());
   }

返回到這個方法org.springframework.boot.SpringApplicationRunListeners#contextLoaded處理監聽器

public void contextLoaded(ConfigurableApplicationContext context) {
   for (SpringApplicationRunListener listener : this.listeners) {
      listener.contextLoaded(context);
   }
}

下面是初始化spring上下文請檢視spring原始碼解析系列文章有詳細的介紹。

初始化spring上下文後進入org.springframework.boot.SpringApplication#afterRefresh這個方法

protected void afterRefresh(ConfigurableApplicationContext context,
      ApplicationArguments args) {
   callRunners(context, args);
}

執行runners進入這個方法org.springframework.boot.SpringApplication#callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
   List<Object> runners = new ArrayList<Object>();
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   AnnotationAwareOrderComparator.sort(runners);
   for (Object runner : new LinkedHashSet<Object>(runners)) {
      if (runner instanceof ApplicationRunner) {
         callRunner((ApplicationRunner) runner, args);
      }
      if (runner instanceof CommandLineRunner) {
         callRunner((CommandLineRunner) runner, args);
      }
   }
}
public interface ApplicationRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming application arguments
    * @throws Exception on error
    */
   void run(ApplicationArguments args) throws Exception;

}

可以實現這個介面在spring上下文初始化完畢後去做一些處理。

進入這個方法org.springframework.boot.SpringApplicationRunListeners#finished

public void finished(ConfigurableApplicationContext context, Throwable exception) {
   for (SpringApplicationRunListener listener : this.listeners) {
      callFinishedListener(listener, context, exception);
   }
}

進入這個方法org.springframework.boot.SpringApplicationRunListeners#callFinishedListener

private void callFinishedListener(SpringApplicationRunListener listener,
      ConfigurableApplicationContext context, Throwable exception) {
   try {
      listener.finished(context, exception);
   }
   catch (Throwable ex) {
      if (exception == null) {
         ReflectionUtils.rethrowRuntimeException(ex);
      }
      if (this.log.isDebugEnabled()) {
         this.log.error("Error handling failed", ex);
      }
      else {
         String message = ex.getMessage();
         message = (message != null) ? message : "no error message";
         this.log.warn("Error handling failed (" + message + ")");
      }
   }
}

執行監聽器的spring上下文載入完畢事件。

 

說在最後

本次僅代表個人觀