SpringBoot 启动类 源码解析 (二 . run() 方法之 prepareEnvironment createApplicationContext 解析)
// * 方法为重要的方法 不加 * 的可以不看 意义不大
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class CmasApplication
{
public static void main(String[] args)
{
// 点击run方法进入
SpringApplication.run(CmasApplication.class, args);
}
}
public class SpringApplication {
// run 方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 通过 run 方法进入 1. new了 一个 SpringApplication 对象 2.调用 run 方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 点击 进入 new SpringApplication 的方法
return new SpringApplication(primarySources).run(args);
}
// new SpringApplication 的方法
public SpringApplication(Class<?>... primarySources) {
// 进入 this 方法
this(null, primarySources);
}
// this 方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// resourceLoader 资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// primarySources 就是当前启动类 CmasApplication
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 该方法表示 当前的web应用类型是否是web项目,debugger返回为 servlet 类型 点击进入 deduceFromClasspath
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// * 设置初始化器 从方法名推断 会 set 一个 初始化器的集合 进入 getSpringFactoriesInstances 方法
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// * 设置监听器 会 set 一个 监听器的集合
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主启动类 也就是我们的 CmasApplication
this.mainApplicationClass = deduceMainApplicationClass();
}
// 获取工厂实例
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) {
// 获取类加载器 (不重要)从类加载器可以知道加载到的所有class文件
ClassLoader classLoader = getClassLoader();
// 根据类型 加载工厂名称放到集合里(也就是全路径的类名称)参数类型 type = ApplicationContextInitializer.class 可以推断是获取上下文相关的初始化器
// debugger 可以看到 返回8个初始化器(org.springframework.boot.devtools.restart.RestartScopeInitializer...)
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// * 通过名称创建 对应的实例 放到集合里 最终返回8个实例对象
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 对实例进行排序,有Order 按照order 排序 没有就按照原本的顺序进行排序 我 debugger 后,结果不是这样,很尴尬 这个排序没懂
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
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;
}
// 实例化方法
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
// 通过构造器 返回实例对象
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
// 从堆栈信息查看该文件是否半酣 main 方法
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
}
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 根据类型获取工厂名 也就是全路径的类名 factoryType = ApplicationContextInitializer.class
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
// 进入方法 META-INF/spring.factories 路径下的所有文件 并通过 getOrDefault 方法进行过滤 (containsKey(key) 文件中的key是否包含 factoryTypeName)
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 {
// classLoader 里面可以获取到已经加载的所有class 类文件 从类文件根据文件名获取 所有 META-INF/spring.factories 路径下的所有文件
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
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 [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
}
public enum WebApplicationType {
/**
* 该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器
*/
NONE,
/**
* 该应用程序应该作为基于 servlet 的 Web 应用程序运行,并且应该启动一个嵌入式 servlet Web 服务器
*/
SERVLET,
/**
* 该应用程序应作为响应式 Web 应用程序运行,并应启动 * 嵌入式响应式 Web 服务器
*/
REACTIVE;
// web 项目包含的 类
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
// 进入 deduceFromClasspath
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;
}
// SERVLET_INDICATOR_CLASSES 是个数组 判断 ClassUtils 是否包含 该数组元素 不包含咋返回 NONE
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 包含一个 则返回 SERVLET
return WebApplicationType.SERVLET;
}
}
总结一下:
1.创建自身实例对象
2.推断是否为web项目
3.设置所有初始化器 设置监听器 (中途 在调用 loadSpringFactories时读取了类路径下所有META-INF/spring.factories下内容,并全部缓存到了SpringFactoriesLoader的cache缓存中)
4.推断主启动类