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; //没有传入resourceLoader
- Assert.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)); # 初始化BootstrapRegistry
- setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContext
- setListeners((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,则为响应式web
- return 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的value
- String[] 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变成不可变list
- result.replaceAll(SpringFactoriesLoader::toDistinctUnmodifiableList);
- }
- catch (IOException ex) {
- throw new IllegalArgumentException("Unable to load factories from location [" + resourceLocation + "]", ex);
- }
- // 表示将result整个map变成不可变map
- return 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)); # 初始化BootstrapRegistry
- setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContext
- setListeners((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`就会被执行。
- @Override
- public void onApplicationEvent(ApplicationEvent event) {
- System.out.println("事件: " + event);
- }
- @Override
- public 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);
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |