Springboot 启动流程(一):
springboot启动时电泳main方法的SpringApplication.run()方法传入class和main方法的args对象
在底层调用了run方法:
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
其中run方法的具体实现:
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
new了一个SpringApplication的对象,传入了class对象再调用run方法实现具体启动逻辑:
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
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();// 给webApplicationType赋值,之后createContent时用到
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));// 把加载出的ApplicationContextInitializer放入initializers中(其中重要的方法:getSpringFactoriesInstances)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 吧加载的Listener放入listeners
this.mainApplicationClass = deduceMainApplicationClass();// 给mainApplication赋值(获取调用Application.run方法的类)
}
上面的代码主要做了初始化变量的工作,其中最重要的方法就是getSpringFactoriesInstances方法:
他调用了pringFactoriesLoader.loadFactoryNames方法,这个方法的实际作用可以看成是预加载,当我们调用这个方法时
会获取所有.factory的配置文件,然后根据传来的names创建对象,具体代码如下:
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();// 获取的是defaultClassLoader(Thread.currentThread().getContextClassLoader())
// 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;
}
SpringFactoriesLoader:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, 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(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 factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
FACTORIES_RESOURCE_LOCATION 这个变量是类中写死的:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
获取对应的classloader的META-INF/spring.factories的配置文件的内容,我们可以看下spring.factories中写的是什么:
org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
上面是其中一个spring.factories中的内容,其实就是一个Factory的类名,loadSpringFactories方法获取了所有spring.factories中的数据
然后放在list中放回给前面的方法,再把list放入缓存中.获取完类名后在调用Application中的createSpringFactoriesInstances方法,
这个方法主要是通过反射获取所有name的对象,代码如下:
@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);// 判断instanceClass是否是type的子类
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;
}
一系列类流程下来,就给所有的initializers和listeners赋值了.
创建完SpringApplication对象后就要调用run方法了.我们先总结下这一块儿代码的流程:
首先调用run方法是会创建SpringApplication的对象,并获取所有的ApplicationContextInitializer对象和ApplicationListener对象,并赋值给
成员变量.最后从stackTrace中找到调用main方法的类并赋值给mainApplicationClass,随后就开始真正的初始化spring的流程了