伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

Spring Boot 2.0(七):SpringApplication 深入探索

来源:本站原创 浏览:114次 时间:2022-03-10


关注我

zhisheng

转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/

前言

在 Spring Boot 项目的启动类中常见代码如下:

1@SpringBootApplication
2public class SpringbotApplication {
3    public static void main(String[] args) {
4        SpringApplication.run(SpringbotApplication.class, args);
5    }
6}

其中也就两个比较引人注意的地方:

  • @SpringBootApplication

  • SpringApplication.run()

对于第一个注解 @SpringBootApplication,我已经在博客 Spring Boot 2.0系列文章(六):Spring Boot 2.0中SpringBootApplication注解详解 中详细的讲解了。接下来就是深入探究第二个了 SpringApplication.run() 。

换个姿势

上面的姿势太简单了,只一行代码就完事了。

1SpringApplication.run(SpringbotApplication.class, args);

其实是支持做一些个性化的设置,接下来我们换个姿势瞧瞧:

1@SpringBootApplication
2public class SpringbotApplication {  
3    public static void main(String[] args) {
4        SpringApplication app = new Spriϣ��,ϣ��ngApplication(SpringbotApplication.class);
5         // 自定义应用程序的配置
6         //app.setXxx()
7         app.run(args)
8    }
9}

没错,就是通过一个构造函数,然后设置相关的属性,从而达到定制化服务。有哪些属性呢?

属性对应的 get/set 方法

看到没,还很多呢!

举个例子:你想把 Spring Boot 项目的默认 Banner 换成你自己的,就需要在这里如下:

 1public static void main(String[] args) {
2//        SpringApplication.run(Springboot2Application.class, args);
3  SpringApplication application = new SpringApplication(Springboot2Application.class);
4  application.setBanner((environment, sourceClass, out) -> {
5    //这里打印一个logo
6    System.out.println("      _      _       _\n" +
7                       "     | |    (_)     | |\n" +
8                       " ____| |__   _  ___ | |__    ___  _ __    __ _\n" +
9                       "|_  /| '_ \\ | |/ __|| '_ \\  / _ \\| '_ \\  / _` |\n" +
10                       " / / | | | || |\\__ \\| | | ||  __/| | | || (_| |\n" +
11                       "/___||_| |_||_||___/|_| |_| \\___||_| |_| \\__, |\n" +
12                       "                                          __/ |\n" +
13                       "                                         |___/\n");
14  });
15  application.setBannerMode(Banner.Mode.CONSOLE);
16  //你还可以干其他的定制化初始设置
17  application.run(args);
18}

现在重启项目,你就会发现,控制台的 logo 已经换成你自己的了。

当然了,你可能会觉得这样写有点复杂,嗯嗯,确实,这样硬编码在代码里确实不太友好。你还可以在src/main/resources路径下新建一个banner.txt文件,banner.txt中填写好需要打印的字符串内容即可。

从该类中可以看到在 Spring Boot 2 中引入了个新的 WebApplicationType 和 WebEnvironment。




确实,这也是 Spring Boot 2 中比较大的特性,它是支持响应式编程的。我之前在文章 Spring Boot 2.0系列文章(二):Spring Boot 2.0 新特性详解 中也介绍过,以后有机会会介绍它的,这里我先卖个关子。

SpringApplication 初始化

SpringApplication.run() 的实现才是我们要深入探究的主角,该方法代码如下:

1//静态方法,可用于使用默认配置运行 SpringApplication
2public static ConfigurableApplicationContext run(Class<?> primarySource,
3      String... args) {
4  return run(new Class<?>[] { primarySource }, args);
5}
6public static ConfigurableApplicationContext run(Class<?>[] primarySources,
7            String[] args) {
8  return new SpringApplication(primarySources).run(args);
9}

在这个静态方法中,创建 SpringApplication 对象,并调用该对象的 run 方法。

 1public SpringApplication(Class<?>... primarySources) {
2  this(null, primarySources);
3}
4//创建一个 SpringApplication 实例,应用上下文会根据指定的主要资源加载 beans ,实例在调用 run 方法之前可以定制化
5@SuppressWarnings({ "unchecked", "rawtypes" })
6public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
7  this.resourceLoader = resourceLoader;
8  Assert.notNull(primarySources, "PrimarySources must not be null");
9  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
10  this.webApplicationType = deduceWebApplicationType();
11  setInitializers((Collection) getSpringFactoriesInstances(
12    ApplicationContextInitializer.class));
13  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
14  this.mainApplicationClass = deduceMainApplicationClass();
15}

首先是进入单个参数的构造方法,然后进入两参数的构造方法(ResourceLoader 为 null),然后进行初始化。

1、deduceWebApplicationType() : 推断应用的类型 ,创建的是一个 SERVLET 应用还是 REACTIVE应用或者是 NONE

 1private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework.web.reactive.DispatcherHandler";
2private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework.web.servlet.DispatcherServlet";
3private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
4            "org.springframework.web.context.ConfigurableWebApplicationContext" };
5
6private WebApplicationType deduceWebApplicationType() {
7  if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
8      && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
9    return WebApplicationType.REACTIVE;    //该程序是 REACTIVE 程序
10  }
11  for (String className : WEB_ENVIRONMENT_CLASSES) {
12    if (!ClassUtils.isPresent(className, null)) {
13      return WebApplicationType.NONE;    //该程序为 NONE
14    }
15  }
16  return WebApplicationType.SERVLET;    //默认返回是 SERVLET 程序
17}

2、setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)):初始化 classpath 下的所有的可用的 ApplicationContextInitializer。

1)、getSpringFactoriesInstances()

 1private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
2  return getSpringFactoriesInstances(type, new Class<?>[] {});
3}
4//获取所有的 Spring 工厂实例
5private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
6Class<?>[] parameterTypes, Object... args) {
7  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
8  // Use names and ensure unique to protect against duplicates
9  Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //获取所有 Spring Factories 的名字
10  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
11                                                     classLoader, args, names);
12  AnnotationAwareOrderComparator.sort(instances); //Spring 工厂实例排序
13  return instances;
14}
15//根据读取到的名字创建对象(Spring 工厂实例)
16private <T> List<T> createSpringFactoriesInstances(Class<T> type,
17 Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
18  List<T> instances = new ArrayList<>(names.size());
19  for (String name : names) {
20    try {
21      Class<?> instanceClass = ClassUtils.forName(name, classLoader);
22      Assert.isAssignable(type, instanceClass);
23      Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
24      T instance = (T) BeanUtils.instantiateClass(constructor, args);
25      instances.add(instance);
26    }
27    catch (Throwable ex) {
28      throw new IllegalArgumentException(
29        "Cannot instantiate " + type + " : " + name, ex);
30    }
31  }
32  return instances;
33}

上面的 SpringFactoriesLoader.loadFactoryNames() ,是从 META-INF/spring.factories 的资源文件中,读取 key 为org.springframework.context.ApplicationContextInitializer 的 value。

而 spring.factories 的部分内容如下:

可以看到,最近的得到的,是 ConfigurationWarningsApplicationContextInitializer,ContextIdApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer 这四个类的名字。

2)、setInitializers():

1public void setInitializers(
2            Collection<? extends ApplicationContextInitializer<?>> initializers) {
3  this.initializers = new ArrayList<>();
4  this.initializers.addAll(initializers);
5}

所以,这里 setInitializers() 所得到的成员变量 initializers 就被初始化为ConfigurationWarningsApplicationContextInitializer,ContextIdApplicationContextInitializer,DelegatingApplicationContextInitializer,ServerPortInfoApplicationContextInitializer 这四个类的对象组成的 list。

3、setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)):初始化 classpath 下的所有的可用的 ApplicationListener。

1)、getSpringFactoriesInstances() 和上面的类似,但是它是从 META-INF/spring.factories 的资源文件中,获取到 key 为 org.springframework.context.ApplicationListener 的 value。

2)、setListeners():

1public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
2  this.listeners = new ArrayList<>();
3  this.listeners.addAll(listeners);
4}

所以,这里 setListeners() 所得到的成员变量 listeners 就被初始化为 ClearCachesApplicationListener,ParentContextCloserApplicationListener,FileEncodingApplicationListener,AnsiOutputApplicationListener ,ConfigFileApplicationListener,DelegatingApplicationListener,ClasspathLoggingApplicationListener,LoggingApplicationListener,LiquibaseServiceLocatorApplicationListener 这九个类的对象组成的 list。

4、deduceMainApplicationClass() :根据调用栈,推断出 main 方法的类名

 1private Class<?> deduceMainApplicationClass() {
2  try {
3    StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
4    for (StackTraceElement stackTraceElement : stackTrace) {
5      if ("main".equals(stackTraceElement.getMethodName())) {
6        return Class.forName(stackTraceElement.getClassName());
7      }
8    }
9  }
10  catch (ClassNotFoundException ex) {
11    // Swallow and continue
12  }
13  return null;
14}
run 方法背后的秘密

上面看完了构造方法后,已经初始化了一个 SpringApplication 对象,接下来调用其 run 方法,代码如下:

 1//运行 Spring 应用程序,创建并刷新一个新的 ApplicationContext
2public ConfigurableApplicationContext run(String... args) {
3        StopWatch stopWatch = new StopWatch();
4        stopWatch.start();
5        ConfigurableApplicationContext context = null;
6        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
7        configureHeadlessProperty();
8        SpringApplicationRunListeners listeners = getRunListeners(args);
9        listeners.starting();
10        try {
11            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
12                    args);
13            ConfigurableEnvironment environment = prepareEnvironment(listeners,
14                    applicationArguments);
15            configureIgnoreBeanInfo(environment);
16            Banner printedBanner = printBanner(environment);
17            context = createApplicationContext();
18            exceptionReporters = getSpringFactoriesInstances(
19                    SpringBootExceptionReporter.class,
20                    new Class[] { ConfigurableApplicationContext.class }, context);
21            prepareContext(context, environment, listeners, applicationArguments,
22                    printedBanner);
23            refreshContext(context);
24            afterRefresh(context, applicationArguments);
25            stopWatch.stop();
26            if (this.logStartupInfo) {
27                new StartupInfoLogger(this.mainApplicationClass)
28                        .logStarted(getApplicationLog(), stopWatch);
29            }
30            listeners.started(context);
31            callRunners(context, applicationArguments);
32        }
33        catch (Throwable ex) {
34            handleRunFailure(context, ex, exceptionReporters, listeners);
35            throw new IllegalStateException(ex);
36        }
37        try {
38            listeners.running(context);
39        }
40        catch (Throwable ex) {
41            handleRunFailure(context, ex, exceptionReporters, null);
42            throw new IllegalStateException(ex);
43        }
44        return context;
45    }

可变个数参数 args 即是我们整个应用程序的入口 main 方法的参数。StopWatch 是来自 org.springframework.util 的工具类,可以用来方便的记录程序的运行时间。

再来看看 1.5.12 与 2.0.1 版本的 run 方法 有什么不一样的地方?

接下来好好分析上面新版本(2.0.1)的 run 方法的代码并配合比较旧版本(1.5.12)。

1、configureHeadlessProperty():设置 headless 模式

1private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
2private boolean headless = true;
3
4private void configureHeadlessProperty() {
5  System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
6    SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
7}

实际上是就是设置系统属性 java.awt.headless,该属性会被设置为 true。

2、getRunListeners():加载 SpringApplicationRunListener 对象

 1 //TODO:  xxx
2SpringApplicationRunListeners listeners = getRunListeners(args);//初始化监听器
3listeners.starting();
4try {
5  prepareContext(context, environment, listeners, applicationArguments, printedBanner);
6  refreshContext(context);
7  afterRefresh(context, applicationArguments);
8  listeners.started(context);
9  callRunners(context, applicationArguments);
10}
11try {
12  listeners.running(context);
13}
14
15private SpringApplicationRunListeners getRunListeners(String[] args) {
16  Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
17  return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
18    SpringApplicationRunListener.class, types, this, args));
19}

上面的 getRunListeners() 中也利用 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringApplicationRunListener 的值,然后再将获取到的值作为参数传递到 SpringApplicationRunListeners 的构造方法中去创建对象。

3、new DefaultApplicationArguments(args) :获取启动时传入参数 args(main 方法传进来的参数) 并初始化为 ApplicationArguments 对象。

1public DefaultApplicationArguments(String[] args) {
2  Assert.notNull(args, "Args must not be null");
3  this.source = new Source(args);
4  this.args = args;
5}

4、prepareEnvironment(listeners, applicationArguments):根据 listeners 和 applicationArguments 配置SpringBoot 应用的环境。

 1private ConfigurableEnvironment prepareEnvironment(
2  SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
3  // Create and configure the environment
4  ConfigurableEnvironment environment = getOrCreateEnvironment();
5  configureEnvironment(environment, applicationArguments.getSourceArgs());
6  listeners.environmentPrepared(environment);
7  bindToSpringApplication(environment);
8  if (this.webApplicationType == WebApplicationType.NONE) {
9    environment = new EnvironmentConverter(getClassLoader())
10      .convertToStandardEnvironmentIfNecessary(environment);
11  }
12  ConfigurationPropertySources.attach(environment);
13  return environment;
14}
15//如果 environment 不为空,直接 get 到,否则创建
16private ConfigurableEnvironment getOrCreateEnvironment() {
17  if (this.environment != null) {
18    return this.environment;
19  }
20  if (this.webApplicationType == WebApplicationType.SERVLET) {
21    return new StandardServletEnvironment();
22  }
23  return new StandardEnvironment();
24}
25//配置环境
26protected void configureEnvironment(ConfigurableEnvironment environment,String[] args) {
27  configurePropertySources(environment, args);//配置要使用的PropertySources
28  configureProfiles(environment, args);//配置要使用的Profiles
29}
30//将环境绑定到 SpringApplication
31protected void bindToSpringApplication(ConfigurableEnvironment environment) {
32  try {
33    Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
34  }
35  catch (Exception ex) {
36    throw new IllegalStateException("Cannot bind to SpringApplication", ex);
37  }
38}

5、configureIgnoreBeanInfo(environment):根据环境信息配置要忽略的 bean 信息

 1public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
2
3private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
4  if (System.getProperty(
5    CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
6    Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
7                                             Boolean.class, Boolean.TRUE);
8    System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
9                       ignore.toString());
10  }
11}

6、printBanner(environment):打印标志,上面我已经说过了。

 1private Banner printBanner(ConfigurableEnvironment environment) {
2  if (this.bannerMode == Banner.Mode.OFF) {    //如果设置为 off,不打印 Banner
3    return null;
4  }
5  ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader
6    : new DefaultResourceLoader(getClassLoader());
7  SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
8    resourceLoader, this.banner);
9  if (this.bannerMode == Mode.LOG) {
10    return bannerPrinter.print(environment, this.mainApplicationClass, logger);
11  }
12  return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
13}

7、createApplicationContext():根据应用类型来确定该 Spring Boot 项目应该创建什么类型的 ApplicationContext ,默认情况下,如果没有明确设置的应用程序上下文或应用程序上下文类,该方法会在返回合适的默认值。

 1public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
2public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
3public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context.annotation.AnnotationConfigApplicationContext";
4
5protected ConfigurableApplicationContext createApplicationContext() {
6  Class<?> contextClass = this.applicationContextClass;
7  if (contextClass == null) {
8    try {
9      switch (this.webApplicationType) {    //根据应用程序的类型来初始化容器
10        case SERVLET:    //servlet 应用程序
11          contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
12          break;
13        case REACTIVE:    //reactive 应用程序
14          contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
15          break;
16        default:        //默认
17          contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
18      }
19    } catch (ClassNotFoundException ex) {
20  throw new IllegalStateException(
21    "Unable create a default ApplicationContext,please specify an             ApplicationContextClass",ex);
22    }
23  }
24  //最后通过Spring的工具类 BeanUtils 初始化容器类 bean
25  return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
26}

来看看在 1.5.12 中是怎么样的?

8、exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context)

 1private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
2            Class<?>[] parameterTypes, Object... args) {
3  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
4  // Use names and ensure unique to protect against duplicates
5  Set<String> names = new LinkedHashSet<>(
6    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
7  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
8       classLoader, args, names);//根据类型 key 为 SpringBootExceptionReporter 去加载
9  AnnotationAwareOrderComparator.sort(instances);//对实例排序
10  return instances;
11}

这里也是通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中 key 为 SpringBootExceptionReporter 的全类名的 value 值。

9、prepareContext(context, environment, listeners, applicationArguments, printedBanner):完成整个容器的创建与启动以及 bean 的注入功能。

 1//装配 Context
2private void prepareContext(ConfigurableApplicationContext context,
3   ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
4   ApplicationArguments applicationArguments, Banner printedBanner) {
5  //将之前准备好的 environment 设置给创建好的 ApplicationContext 使用
6  context.setEnvironment(environment);
7  //1、
8  postProcessApplicationContext(context);
9  //2、
10  applyInitializers(context);
11  listeners.contextPrepared(context);
12  if (this.logStartupInfo) {//启动日志
13    logStartupInfo(context.getParent() == null);
14    logStartupProfileInfo(context);
15  }
16  // Add boot specific singleton beans
17  context.getBeanFactory().registerSingleton("springApplicationArguments",
18                                             applicationArguments);
19  if (printedBanner != null) {
20    context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
21  }
22  // Load the sources
23  Set<Object> sources = getAllSources();
24  Assert.notEmpty(sources, "Sources must not be empty");
25  //3、
26  load(context, sources.toArray(new Object[0]));
27  listeners.contextLoaded(context);
28}

1)、postProcessApplicationContext(context)

 1public static final String CONFIGURATION_BEAN_NAME_GENERATOR = "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
2
3protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
4  if (this.beanNameGenerator != null) {
5    context.getBeanFactory().registerSingleton(
6      AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
7      this.beanNameGenerator);
8  }
9  if (this.resourceLoader != null) {
10    if (context instanceof GenericApplicationContext) {
11      ((GenericApplicationContext) context)
12      .setResourceLoader(this.resourceLoader);
13    }
14    if (context instanceof DefaultResourceLoader) {
15      ((DefaultResourceLoader) context)
16      .setClassLoader(this.resourceLoader.getClassLoader());
17    }
18  }
19}

该方法对 context 进行了预设置,设置了 ResourceLoader 和 ClassLoader,并向 bean 工厂中添加了一个beanNameGenerator 。

2)、applyInitializers(context)

1protected void applyInitializers(ConfigurableApplicationContext context) {
2  for (ApplicationContextInitializer initializer : getInitializers()) {
3    Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
4      initializer.getClass(), ApplicationContextInitializer.class);
5    Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
6    initializer.initialize(context);
7  }
8}

在刷新之前将任何 ApplicationContextInitializer 应用于上下文

3)、load(context, sources.toArray(new Object[0]))

主要是加载各种 beans 到 ApplicationContext 对象中。

 1protected void load(ApplicationContext context, Object[] sources) {
2  BeanDefinitionLoader loader = createBeanDefinitionLoader( //2
3    getBeanDefinitionRegistry(context), sources);// 1
4  if (this.beanNameGenerator != null) {
5    loader.setBeanNameGenerator(this.beanNameGenerator);
6  }
7  if (this.resourceLoader != null) {
8    loader.setResourceLoader(this.resourceLoader);
9  }
10  if (this.environment != null) {
11    loader.setEnvironment(this.environment);
12  }
13  loader.load();//3
14}

(1)、getBeanDefinitionRegistry(context)

获取 bean 定义注册表

 1private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
2  if (context instanceof BeanDefinitionRegistry) {
3    return (BeanDefinitionRegistry) context;
4  }
5  if (context instanceof AbstractApplicationContext) {
6    return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
7      .getBeanFactory();
8  }
9  throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
10}

(2)、createBeanDefinitionLoader()

通过 BeanDefinitionLoader 的构造方法把参数(注册表、资源)传进去,然后创建 BeanDefinitionLoader。

(3)、load()

把资源全部加载。

10、refreshContext(context)

 1private void refreshContext(ConfigurableApplicationContext context) {
2  refresh(context);//1
3  if (this.registerShutdownHook) {
4    try {
5      context.registerShutdownHook();
6    }
7    catch (AccessControlException ex) {
8      // Not allowed in some environments.
9    }
10  }
11}
12//刷新底层的 ApplicationContext
13protected void refresh(ApplicationContext applicationContext) {
14  Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
15  ((AbstractApplicationContext) applicationContext).refresh();
16}

refreshContext(context) 方法又调用了 refresh(context)。在调用了 refresh(context) 方法之后,调用了 registerShutdownHook 方法。继续看它的 refresh 方法:

 1public void refresh() throws BeansException, IllegalStateException {
2  synchronized (this.startupShutdownMonitor) {
3    // Prepare this context for refreshing.
4    prepareRefresh();
5    // Tell the subclass to refresh the internal bean factory.
6    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
7    // Prepare the bean factory for use in this context.
8    prepareBeanFactory(beanFactory);
9    try {
10      // Allows post-processing of the bean factory in context subclasses.
11      postProcessBeanFactory(beanFactory);
12      // Invoke factory processors registered as beans in the context.
13      invokeBeanFactoryPostProcessors(beanFactory);
14      // Register bean processors that intercept bean creation.
15      registerBeanPostProcessors(beanFactory);
16      // Initialize message source for this context.
17      initMessageSource();
18      // Initialize event multicaster for this context.
19      initApplicationEventMulticaster();
20      // Initialize other special beans in specific context subclasses.
21      onRefresh();
22      // Check for listener beans and register them.
23      registerListeners();
24      // Instantiate all remaining (non-lazy-init) singletons.
25      finishBeanFactoryInitialization(beanFactory); //1
26      // Last step: publish corresponding event.
27      finishRefresh();
28    } catch (BeansException ex) {
29      。。。
30        // Destroy already created singletons to avoid dangling resources.
31        destroyBeans();
32      // Reset 'active' flag.
33      cancelRefresh(ex);
34      // Propagate exception to caller.
35      throw ex;
36    } finally {
37      // Reset common introspection caches in Spring's core, since we
38      // might not ever need metadata for singleton beans anymore...
39      resetCommonCaches();
40    }
41  }
42}

到这里,我们就看见重点了,仔细看上的注释,正在做各种初始化工作,而今天我们关注的重点就是方法 finishBeanFactoryInitialization(beanFactory)。该方法进行了非懒加载 beans 的初始化工作。现在我们进入该方法内部,一探究竟。

  • 上一篇: SpringBoot2.0系列文章(六)中SpringBootApplication注解详解
  • 下一篇: Spring Boot 2.0系列文章(三):Spring Boot 2.0 配置改变
  •   推荐站点

    • At-lib分类目录At-lib分类目录

      At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

      www.at-lib.cn
    • 中国链接目录中国链接目录

      中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

      www.cnlink.org
    • 35目录网35目录网

      35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

      www.35mulu.com
    • 就要爱网站目录就要爱网站目录

      就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

      www.912219.com
    • 伍佰目录伍佰目录

      伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

      www.wbwb.net