1. 程式人生 > >Springboot源碼深度解析,方法解析,類加載解析,容器建立

Springboot源碼深度解析,方法解析,類加載解析,容器建立

加載類 duplicate turn getclass for main方法 gin unique 所有

springboot的啟動都是從main方法開始的,如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

後面會進入SpringApplication的初始化方法:
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
public SpringApplication(Object... sources) {
initialize(sources);
}
我們進入initialize(Object[] sources)查看邏輯:
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();
}

deduceWebEnvironment()方法是驗證是否有web運行的環境,方法就是查看下tomcat以及spring中的某個類是否存在,以此來驗證是否有web環境運行條件,代碼如下:
private boolean deduceWebEnvironment() {
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return false;
}
}
return true;
}
initialize()方法中的第二個方法就是

setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
這個方法後面會進入getSpringFactoriesInstances方法,其內容如下:

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;
}
上面方法中:

第一個方法獲取了當前加載類的classLoader,即加載第三方類庫的AppClassLoader。
第二個方法是加載了所有jar包以及classes下面的所有“META-INF/spring.factories”文件,並將其key為“org.springframework.context.ApplicationContextInitializer”的所有value放入了一個集合中,為了避免重復,放入了一個Set集合中將數據返回。其包含的類型有如下幾種,即names的Set集合中的值有如下幾種:
0 = "org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer"
1 = "org.springframework.boot.context.ContextIdApplicationContextInitializer"
2 = "org.springframework.boot.context.config.DelegatingApplicationContextInitializer"
3 = "org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer"
4 = "org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"


3.第三個方法createSpringFactoriesInstances是創建了上述類型的實例,

4.第四個方法AnnotationAwareOrderComparator.sort(instances);會根據AnnotationAwareOrderComparator的排序規則進行排序執行,將instances進行排序。

最後在外面將這些排序好的initializers設置到了SpringApplication的initializers的屬性之中。

在springApplication的initialize方法的後面一個方法setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));中是設置org.springframework.context.ApplicationListener類的實例到類SpringApplication的listeners屬性當中。

springApplication的initialize方法中的最後一個方法this.mainApplicationClass = deduceMainApplicationClass();是獲取啟動類,其方法如下:

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;
}
是通過RuntimeException尋找棧軌跡打印的方法中獲取main方法的類,以此來獲得啟動類。

至此,關於initialize方法的所有過程就說完了。下面我們就要進入run方法的過程說明了。
---------------------
作者:lz710117239
來源:CSDN
原文:https://blog.csdn.net/lz710117239/article/details/80068588
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

Springboot源碼深度解析,方法解析,類加載解析,容器建立