Spring Boot启动方法的改造
public static void main(String[] args) {
SpringApplication.run(DILoopApplication.class, args);
}
Spring Boot的启动的这行代码,内部就是执行了SpringApplication的一个静态方法run。进入这个run方法:
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
当调用SpringApplication.run方法后,该方法会继续调用第2个run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
发现在第2个run方法中new了一个新的SpringApplication对象,并调用了run方法,传入args参数。也就意味着这一行代码可以改写成下面这个样子:
public static void main(String[] args) {
//SpringApplication.run(DILoopApplication.class, args);
SpringApplication sbapp = new SpringApplication(DILoopApplication.class);
ConfigurableApplicationContext context = sbapp.run(args);
}
SpringApplication的构造函数
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
构造函数代码比较少,我们来一行一行的分析
1:WebApplicationType
构造函数中通过WebApplicationType.deduceFromClasspath()来获取这个变量。然后看下他的定义
public enum WebApplicationType {
NONE,
SERVLET,
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org."
+ "springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
WebApplicationType其实就是一个枚举,定义了三个应用类型:
• NONE:不作为web应用启动,依赖外部web server。
• SERVLET:基于servlet的web应用启动, 使用内嵌 web server。
• REACTIVE:响应式web应用启动,使用内嵌的响应式web server。
然后来看下Spring boot的推断过程
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
ClassUtils.isPresent主要工作就是通过传入的类名,在应用程序里反射,如果反射成功返回true, 反射失败返回 false
Case 1: class path 中存在类org.springframework.web.reactive.DispatcherHandler同时不存在类org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer 那应用就是REACTIVE类型
Case 2: 在class path 中同时存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext那应用就是SERVLET类型
CASE 3: 既不属于case1, 也不属于case2那应用就是NONE类型
2:setInitializers
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
this.initializers.addAll(initializers);
}
这个函数很简单就是把将getSpringFactoriesInstances的返回结果全部添加到成员变量initializers数组中。
下面主要来看getSpringFactoriesInstances函数,他的主要功能就是扫描应用程序的所有jar包,然后读取jar中meta-inf/factory.properties文件中配置的ApplicationContextInitializer类,加载到内存中,并反射创建出具体对象。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
getSpringFactoriesInstances函数中又调用了SpringFactoriesLoader.loadFactoryNames,
这个函数的功能就是遍历所有的jar包并扫描jar下的factory.properties文件。然后解析文件中的所有的properties,并保存到缓冲中。函数loadSpringFactoires执行完后会返回一个key-value的map,然后spring boot又通过getOrDefault函数来过滤了一遍返回值(只获取key是ApplicationContextInitializer类的value)
<font color=red>后面会写一个小case来说明这个getOrDefault的功能。</font>
下面是loadFactory的部分源代码:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
for(int var11 = 0; var11 < var10; ++var11) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
}
然后再回到getSpringFactoriesInstances,看一下他里面调用的createSpringFactoriesInstances方法,这个函数功能很简单就是,将上一步获取到的所有类全名,进行创建并load到内存中。( 循环names集合,先进行forName加载获取反射出class对象,然后再调用他的构造函数初始化对象信息。)
下面是部分源代码:
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
}
catch (Throwable ex) {}
}
}
}
3:setListeners
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>();
this.listeners.addAll(listeners);
}
这个函数很简单就是把将getSpringFactoriesInstances的返回结果全部添加到成员变量listeners数组中。
setListeners中调用的getSpringFactoriesInstances流程和setInitializers时执行逻辑是一样的,只是传入的参数不一样了,setListeners是传入的参数是ApplicationListener
deduceMainApplicationClass
最后一步就是创建springboot的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;
}
getOrDefault(Object key, V defaultValue)
当map中存在该key时,返回该key对应的value,如果map中不存在该key时,则返回defaultValue
Map<String, Integer> name_age = new HashMap<>();
name_age.put("qingfen", 16);
name_age.put("lantian", 17);
name_age.put("baiyun", 18);
int mm = name_age.getOrDefault("qingfen", 99);
int mm1 = name_age.getOrDefault("lantian2", 99);
System.out.println("在map中找到数据,getOrDefault返回的数据" + mm);
System.out.println("在map中找不到数据,getOrDefault返回的数据" + mm1);
Map中可以查询到qingfen,所以返回qingfen对应 的Value16,但在查询不到lantian2,所以返回给定的默认值99。