SpringApplication_0">SpringApplication
@SpringBootApplication
@ComponentScan(basePackages = { "com.example.*" })
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args); // Spirngboot程序入口}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {// 首先用主类(DemoApplication.class)为参数调用构造器方法,之后执行run()方法return new SpringApplication(primarySources).run(args);
}
构造器方法
第一个参数ResourceLoader
是资源加载器,它定义获取资源的策略。它加载各种来源的资源,比如文件资源(file:/var/local/a.txt
),类路径资源(classpath: application.yml
),URL资源(URL:https://www.baidu.com
),并且统一封装为Resource
对象。
Resource
对象是对各种资源的抽象,调用Resource
对象不用考虑底层实现。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader; //没有传入resourceLoaderAssert.notNull(primarySources, "PrimarySources must not be null"); // 参数校验this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath(); # 判断服务类型this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); # 初始化BootstrapRegistrysetInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContextsetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); # this.mainApplicationClass = deduceMainApplicationClass();
}
判断服务类型
WebApplicationType
是枚举类,有3种类型
NONE
表示非web应用,不需要web服务器SERVLET
表示基于SERVLET的WEB应用,需要SERVLET服务器REACTIVE
表示响应式WEB应用,需要响应式web服务器
spring-mvc
默认使用的Tomcat
属于第二种,因此springApplication.webApplicationType = SERVLET
,后续在refresh()
方法里会启动Tomcat
。
ClassUtils.isPresent
调用Class.forName()
方法查询类路径上是否存在某个类。
public enum WebApplicationType {NONE,SERVLET,REACTIVE;private static final String[] SERVLET_INDICATOR_CLASSES = { "jakarta.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {// 如果JVM无法加载WEBMVC_INDICATOR_CLASS类和JERSEY_INDICATOR_CLASS// 但是JVM可以加载WEBFLUX_INDICATOR_CLASS,则为响应式webreturn WebApplicationType.REACTIVE;}// 只要没有SERVLET_INDICATOR_CLASSES 中任意一个类,都属于非WEB服务for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}// 同时包含SERVLET_INDICATOR_CLASSES的所有类,属于SERVELT web服务return WebApplicationType.SERVLET;}
}
getSpringFactoriesInstances
private <T> List<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, null);
}
private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
}
public static SpringFactoriesLoader forDefaultResourceLocation(@Nullable ClassLoader classLoader) {return forResourceLocation(FACTORIES_RESOURCE_LOCATION, classLoader);
}
getSpringFactoriesInstances
方法分2步.第一步加载工厂类SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader())
,DefaultResourceLocation
就是"META-INF/spring.factories"
.第二步实例化工厂类load(type, argumentResolver)
。
加载工厂类
public class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";static final Map<ClassLoader, Map<String, SpringFactoriesLoader>> cache = new ConcurrentReferenceHashMap<>();// 加载"META-INF/spring.factories"工厂类的类加载器private final ClassLoader classLoader;private final Map<String, List<String>> factories;// 默认加载"META-INF/spring.factories"中的类public static SpringFactoriesLoader forDefaultResourceLocation(@Nullable ClassLoader classLoader) {return forResourceLocation(FACTORIES_RESOURCE_LOCATION, classLoader);}
}
SpringFactoriesLoader
是spring.factories
工厂类文件的加载器。forDefaultResourceLocation
静态方法表示默认从每个jar包的"META-INF/spring.factories"
文件加载类。
forResourceLocation
静态方法实现加载工厂类并且保存在SpringFactoriesLoader
类对象的静态变量cache
中,每次调用getSpringFactoriesInstances
方法就不用重复加载"META-INF/spring.factories"
。
public static SpringFactoriesLoader forResourceLocation(String resourceLocation, @Nullable ClassLoader classLoader) {Assert.hasText(resourceLocation, "'resourceLocation' must not be empty");// 获得类加载器,用于加载类,是AppClassLoader系统类加载器ClassLoader resourceClassLoader = (classLoader != null ? classLoader :SpringFactoriesLoader.class.getClassLoader());// loaders是当前类加载器所加载的资源键值对,key是资源名称,是`META-INF/spring.factories`,value是SpringFactoriesLoader对象// cache是类的静态变量,全局唯一Map<String, SpringFactoriesLoader> loaders = cache.computeIfAbsent(resourceClassLoader, key -> new ConcurrentReferenceHashMap<>());return loaders.computeIfAbsent(resourceLocation, key ->new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation)));
}
loadFactoriesResource
实现用AppClassLoader
加载"META-INF/spring.factories"
。结合下图分析源码。
protected static Map<String, List<String>> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) {Map<String, List<String>> result = new LinkedHashMap<>();try {// Enumeration不是枚举类,是迭代器类Enumeration<URL> urls = classLoader.getResources(resourceLocation);while (urls.hasMoreElements()) {// resource是`META-INF/spring.factories`文件的路径UrlResource resource = new UrlResource(urls.nextElement());// Properties类定义:`class Properties extends Hashtable<Object,Object>`// Properties类是线程安全的属性类,用键值对表示属性Properties properties = PropertiesLoaderUtils.loadProperties(resource);properties.forEach((name, value) -> {// 将键值对的值用逗号分隔开,并且将其放入result的valueString[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) value);List<String> implementations = result.computeIfAbsent(((String) name).trim(),key -> new ArrayList<>(factoryImplementationNames.length));Arrays.stream(factoryImplementationNames).map(String::trim).forEach(implementations::add);});}// 表示将result的value变成不可变listresult.replaceAll(SpringFactoriesLoader::toDistinctUnmodifiableList);}catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" + resourceLocation + "]", ex);}// 表示将result整个map变成不可变mapreturn Collections.unmodifiableMap(result);
}
图中的spirng.factories
是本项目自定义的。Springboot
会加载所有包的spring.factories
。比如:spring-boot-autoconfigure-3.3.5.jar!/META-INF/spring.factories, spring-data-redis-3.3.5.jar!/META-INF/spring.factories
。
实例化工厂类
SpringApplication
构造器方法里setInitializers
方法的参数ApplicationContextInitializer.class
用于实例化该接口的实现类,即factoryType
。
load
方法首先根据factoryType
参数获取实现类的全限定类名,之后实例化。
public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver) {return load(factoryType, argumentResolver, null);
}
public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver,@Nullable FailureHandler failureHandler) {Assert.notNull(factoryType, "'factoryType' must not be null");// loadFactoryNames方法就是获取cache中保存的`factoryType`的实现类全限定类名List<String> implementationNames = loadFactoryNames(factoryType);logger.trace(LogMessage.format("Loaded [%s] names: %s", factoryType.getName(), implementationNames));List<T> result = new ArrayList<>(implementationNames.size());FailureHandler failureHandlerToUse = (failureHandler != null) ? failureHandler : THROWING_FAILURE_HANDLER;for (String implementationName : implementationNames) {// 实例化对象T factory = instantiateFactory(implementationName, factoryType, argumentResolver, failureHandlerToUse);if (factory != null) {result.add(factory);}}AnnotationAwareOrderComparator.sort(result);return result;
}
protected <T> T instantiateFactory(String implementationName, Class<T> type,@Nullable ArgumentResolver argumentResolver, FailureHandler failureHandler) {try {// 在JVM中加载implementationName实现类Class<?> factoryImplementationClass = ClassUtils.forName(implementationName, this.classLoader);// 校验实现类是否是type的子类Assert.isTrue(type.isAssignableFrom(factoryImplementationClass), () ->"Class [%s] is not assignable to factory type [%s]".formatted(implementationName, type.getName()));// FactoryInstantiator<T>获得`factoryImplementationClass`类的构造器对象`Constructor<T>`FactoryInstantiator<T> factoryInstantiator = FactoryInstantiator.forClass(factoryImplementationClass);// 调用构造器对象的`constructor.newInstance(args)`方法生成对象。return factoryInstantiator.instantiate(argumentResolver);}catch (Throwable ex) {failureHandler.handleFailure(type, implementationName, ex);return null;}}
初始化
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); # 初始化BootstrapRegistrysetInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContextsetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
上下文
this.bootstrapRegistryInitializers
加载META-INF/spring.factories
中BootstrapRegistryInitializer.class
的实现类,用于初始化DefaultBootstrapContext
上下文对象。而setInitializers
加载ApplicationContextInitializer.class
的实现类,用于初始化ApplicationContext
上下文对象。
这两个上下文,前者是引导上下文,在IOC容器启动之前保存预先加载的类,IOC容器启动之后会销毁引导上下文。一般springboot项目用不到引导上下文
,springcloud
中有用到。
后者就是IOC容器。SpringBoot
默认加载图中7个初始化器。
监听器
setListeners
方法加载ApplicationListener.class
的实现类,用于监听启动SpringApplication
定义的事件。
具体流程是,自定义SpringApplicationRunListener
实现类,定义监听的事件。
public class MyListener implements ApplicationListener<ApplicationEvent> {// 当出现事件(`ApplicationEvent`的实现类),`onApplicationEvent`就会被执行。@Overridepublic void onApplicationEvent(ApplicationEvent event) {System.out.println("事件: " + event);}@Overridepublic boolean supportsAsyncExecution() {return ApplicationListener.super.supportsAsyncExecution();}
}
在META-INF/spring.factories
加一org.springframework.context.ApplicationListener=com.example.demo.MyListener
。
启动项目,加载的实现类中就包含自定义的实现类。
deduceMainApplicationClass
推导主类。源码表示:在(栈帧StackWalker
对象)中找到第一个名称为main
的方法,该方法所在的类就是主类。
private Class<?> deduceMainApplicationClass() {return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(this::findMainClass).orElse(null);
}
private Optional<Class<?>> findMainClass(Stream<StackFrame> stack) {return stack.filter((frame) -> Objects.equals(frame.getMethodName(), "main")).findFirst().map(StackWalker.StackFrame::getDeclaringClass);
}