当前所有项目都用到了springboot,至于刚接触springboot的同学,这边文章不予介绍,度娘有很多,自行去看。
这边文章主要针对启动springboot的源码分析。
分析springboot源码:
1.首先从我们自己的main方法中进入的源码是这个方法,从字面意思可以看出可以配置应用上下文,也就是环境,这个方法我理解真正进入run方法的一个工具方法,为了自定义类中main方法调用,source参数含义是自定义类的class,args是main方法中的参数
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
2.这个方法是springApplication类构造方法执行和真正run方法执行
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
2.1首先是构造方法的执行,首先从字面意思看这个方法初始化,具体初始化什么东西我们看里面的逻辑
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();
}
2.1.1 这个逻辑只是把我们自定义的类对象添加的全局set集合中,具体什么用法现在还没有看出来
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
2.1.2 首先从字面意思看这个方法是,推导出web 环境,判断当前是否是web环境
this.webEnvironment = deduceWebEnvironment();
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
2.1.3 然后在setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class)); 执行了获取spring工程实例的方法如下:
a.这个方法首先是获取当前线程上下文类对象
b.然后通过spring工厂加载器读取工厂名字SET通过传入集合ApplicationContextInitializer 和单签类加载器对象
c.然后再是创建spring工厂实例List集合
d.通过比较AnnotationAwareOrderComparator 对上面查询的工厂实例进行排序
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
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
2.1.3.1 最后执行这个方法:从字面意思看是设置spring工厂集合实例,添加到全局initializers中去,
initializers这个作用是一个存储初始化后应该上下文子类 这个存储的是spring工厂实例集合
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
2.1.4 这个和上面分析是一样的 只是传入的参数不同,结果是获取监听实例然和存储到全局变量listeners中去
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
2.1.5 最后这个方面就是推到拿到我们自定义启动main方法的类存储到mainApplicationClass全局变量中
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;
}
以上就是springboot项目启动时,SpringApplication构造器初始化源码分析
结论:springboot在使用构造器进入初始化时:
第一:存储我们自定义启动类,把这个对象存放到全局变量sources集合中
第二:通过 源码中这个WEB_ENVIRONMENT_CLASSES这个全部静态变量数据推导出环境是不是web环境
第三:设置初始化器,通过initializers全局变量存储 ApplicationContextInitializer spring工厂中实例
第四:设置监听器,通过listeners全局变量存储ApplicationListener spring工厂实例
最后就是拿到我们自己定义启动springboot的类存在该类Class对象
持不同意见的同学可以评论,一起交流,一起进步。