启动
@SpringBootApplication //springboot的核心注解
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
//run(args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//见2.1推断当前环境为哪种环境WebApplicationType
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//见2.2初始化initializers,即设置应用上下文初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//见2.3初始化listeners,即设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//见2.4推断应用的入口类
this.mainApplicationClass = deduceMainApplicationClass();
}
2.1推断当前环境为哪种环境WebApplicationType
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)
&& !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", null)) {
return WebApplicationType.REACTIVE;
}
final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
代码逻辑:
- 如果满足该条件(加载字节码文件DispatcherHandler成功 && DispatcherServlet失败 && ServletContainer失败)则设置app类型为REACTIVE;
- 如果满足该条件(加载字节码文件Servlet失败 || ConfigurableWebApplicationContext失败)则设置app类型为NONE;
- 其他为SERVLET。
(其实加载字节码文件就是有没有引入这个类,idea中按shift+shift搜索一下就可以)
返回值为WebApplicationType枚举类型,有三种
- NONE
- SERVLET
- REACTIVE 请求响应式
2.2
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.resourceLoader != null ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader();
//见2.2.1
//返回值为所有META-INF/spring.factories文件中key=org.springframework.context.ApplicationContextInitializer的value:
//org.springframework.boot.context. ConfigurationWarningsApplicationContextInitializer
//org.springframework.boot.context. ContextIdApplicationContextInitializer
//org.springframework.boot.context.config. DelegatingApplicationContextInitializer
//org.springframework.boot.rsocket.context. RSocketPortInfoApplicationContextInitializer
//org.springframework.boot.web.context. ServerPortInfoApplicationContextInitializer
//org.springframework.boot.autoconfigure. SharedMetadataReaderFactoryContextInitializer
//org.springframework.boot.autoconfigure.logging. ConditionEvaluationReportLoggingListener
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序,重写了compareTo方法,回调getOrder()方法得到一个整形数字,就是决定顺序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
@SuppressWarnings("unchecked")
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);
//通过构造器new实例对象
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
返回值有7个实例对象:为所有META-INF/spring.factories文件中key=org.springframework.context.ApplicationContextInitializer的value:
- org.springframework.boot.context.config.DelegatingApplicationContextInitializer
- org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
- org.springframework.boot.context.ContextIdApplicationContextInitializer
- org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
- org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer
- org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
- org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
2.2.1加载META/INF/spring.factories文件中的所有属性并缓存如cache,key为factories文件中的key,value为值数组
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
"META-INF/spring.factories"+ "]", ex);
}
}
2.3获取方式同2.2,此时key=org.springframework.context.ApplicationListener,有10种
- org.springframework.boot.context.config.ConfigFileApplicationListener
- org.springframework.boot.context.config.AnsiOutputApplicationListener
- org.springframework.boot.context.logging.LoggingApplicationListener
- org.springframework.boot.context.logging.ClasspathLoggingApplicationListener
- org.springframework.boot.autoconfigure.BackgroundPreinitializer
- org.springframework.boot.context.config.DelegatingApplicationListener
- org.springframework.boot.builder.ParentContextCloserApplicationListener
- org.springframework.boot.ClearCachesApplicationListener
- org.springframework.boot.context.FileEncodingApplicationListener
- org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
在通过反射调用上述10个类的无参构造器new实例时,都没有额外的初始化工作。
2.4推断应用的入口类
private Class<?> deduceMainApplicationClass() {
try {
//StackTrace(堆栈轨迹)存放的就是方法调用栈的信息
//获取StackTraceElement的方法有两种,均返回StackTraceElement数组,也就是这个栈的信息。
//1、Thread.currentThread().getStackTrace()
//2、new Throwable().getStackTrace()
//StackTraceElement数组包含了StackTrace(堆栈轨迹)的内容,通过遍历它可以得到方法间的调用过程,即可以得到当前方法以及其调用 //者的方法名、调用行数等信息
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
}
return null;
}