SpringBoot的启动过程(源码分析)主要针对run方法

SpringBoot的启动:(主要在于@SpringBootApplication注解和run方法)

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@SpringBootApplication:待定专门用一篇文章去讲解

 

进入run方法:

public static ConfigurableApplicationContext run(Class<?>[] primarySources,
            String[] args) {
  return new SpringApplication(primarySources).run(args);
}

 

首先要创建了一个SpringApplication对象

在SpringApplication构造方法内部会调用initialize方法:

public SpringApplication(Object... sources) {
  initialize(sources);  //sources目前是一个MyApplication的class对象,MyApplication.class作为参数传了进来
}
private void initialize(Object[] sources) {
  if (sources != null && sources.length > 0) {
    this.sources.addAll(Arrays.asList(sources)); // 把sources设置到SpringApplication的sources属性中,目前只是一个MyApplication类对象
  }
  this.webEnvironment = deduceWebEnvironment(); // 判断是否是web程序(javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext都必须在类加载器中存在),并设置到webEnvironment属性中
  
//从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。初始化classpath下所有可用的ApplicationContextInitializer,这个过程也就是找出所有的应用程序初始化器 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));

//从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。初始化classpath下所有可用的ApplicationListener,这个过程就是找出所有的应用程序事件监听器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //找出main类,这里是MyApplication类,方法内部通过调用栈来推断main方法的类名 this.mainApplicationClass = deduceMainApplicationClass(); }

理解getSpringFactoriesInstances方法:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
  return getSpringFactoriesInstances(type, new Class<?>[] {});
}
//获取所有的 Spring 工厂实例
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  // Use names and ensure unique to protect against duplicates
  Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //获取所有 Spring Factories 的名字
  List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                                                     classLoader, args, names);
  AnnotationAwareOrderComparator.sort(instances); //Spring 工厂实例排序
  return instances;
}
//根据读取到的名字创建对象(Spring 工厂实例),全部都是通过反射创建的
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
 Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
  List<T> instances = new ArrayList<>(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;
}

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

setInitializers方法就是把创建好的对象(List结构)设置到SpringApplication对象的initializers属性当中

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

以上就完成了初始化SpringApplication对象,然后调用它的run方法:

https://www.cnblogs.com/trgl/p/7353782.html

https://juejin.im/post/5b79a6e651882542aa1b2c22

关于ApplicationContextInitializer(接口,里面有initialize方法)在spring上下文初始化的回调函数在上下文(ConfigurableApplicationContext)刷新(refresh)之前调用,做一些容器的初始化工作。

关于ApplicationContextInitializer的注册方式https://www.jianshu.com/p/3828e93be20d

ApplicationListener,主要是在容器初始化完成以后做的一些回调操作,比如一些数据的加载、初始化缓存

public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent>{
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("初始化时我被调用了。");
    }
}

 

posted @ 2019-06-12 00:24  LeeJuly  阅读(591)  评论(0)    收藏  举报