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("初始化时我被调用了。"); } }
本文来自博客园,作者:LeeJuly,转载请注明原文链接:https://www.cnblogs.com/peterleee/p/11007104.html

浙公网安备 33010602011771号