总算是怀着热切的心情打开了spring boot的源码,不知道能看到怎么样的结果,不过算是能压抑期末考紧张的心情。
启动类,都是调用SpringApplication的run()方法,传入的是加入@Configuration注解的类,跟参数。
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);
}
先初始化了SpringApplication的实例然后调用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 = deduceWebApplicationType();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
在其双参构造方法中可以看到,先是保存传入的resourceLoader,对资源非null断言,将资源primarySources按照有序LinkedSet形式存储,调用deduceWebApplication()方法推断出webApplication的类型,然后设置initializers、listeners、用deduceMainApplicationClass()方法得出并设置mainApplicationClass。
先看deduceWebApplication()方法
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
可以看到这里通过ClassUtils类的isPresent()方法检查classpath中是否有相应的类来判断类型。
private static final String[] WEB_ENVIRONMENT_CLASSES =
{ "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";
如果有dispatcherHandler,且没有DispatcherServlet、jersy的就是Reactive类型,如果没有WEB_ENVIRONMENT_CLASSES
指定的类,那么则None类型,否则Servlet类型。
在设置Initializers时首先调用getSpringFactoriesInstances()方法加载ApplicationContextInitializer,然后直接赋值给initializers。
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 = 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;
}
可以看到这里通过spring容器来实现IoC。先得到contextClassLoader,然后调用SpringFactoriesLoader的loadFactoryNames传入factoryClass得到该Class下配置的类名的集合,这里使用set来存,保证类名不重复。然后调用createSpringFactoriesInstances()方法,得到对应的实例的集合,再排序返回。
我们先来看下loadFactoryNames()方法的逻辑。
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
先得到factoryClass的名字,这里即org.springframework.context.ApplicationContextInitializer,然后调用loadSpringFactories()传入ClassLoader,得到map,然后用factoryClass的名字作为key去get。