springboot源码解析(一)初始化方法

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  Collection getSpringFactoriesInstances(Class type,
			Class[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set names = new LinkedHashSet(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

上面方法中:

  1. 第一个方法获取了当前加载类的classLoader,即加载第三方类库的AppClassLoader。
  2. 第二个方法是加载了所有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方法的过程说明了。

你可能感兴趣的:(spring,boot源码,SpringBoot源码)