SpringBoot 启动类 SpringApplication 一 构造器方法

打印 上一主题 下一主题

主题 795|帖子 795|积分 2387

SpringApplication

  1. @SpringBootApplication
  2. @ComponentScan(basePackages = { "com.example.*" })
  3. public class DemoApplication {
  4.         public static void main(String[] args) {
  5.                 SpringApplication.run(DemoApplication.class, args); // Spirngboot程序入口
  6.         }
  7. }
  8. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  9.         return run(new Class<?>[] { primarySource }, args);
  10. }
  11. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  12.     // 首先用主类(DemoApplication.class)为参数调用构造器方法,之后执行run()方法
  13.         return new SpringApplication(primarySources).run(args);
  14. }
复制代码
构造器方法

第一个参数ResourceLoader是资源加载器,它界说获取资源的策略。它加载各种来源的资源,比如文件资源(file:/var/local/a.txt),类路径资源(classpath: application.yml),URL资源(URL:https://www.baidu.com),而且统一封装为Resource对象。
Resource对象是对各种资源的抽象,调用Resource对象不消思量底层实现。
  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2.         this.resourceLoader = resourceLoader; //没有传入resourceLoader
  3.         Assert.notNull(primarySources, "PrimarySources must not be null"); // 参数校验
  4.         this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5.         this.webApplicationType = WebApplicationType.deduceFromClasspath(); # 判断服务类型
  6.         this.bootstrapRegistryInitializers = new ArrayList<>(
  7.                         getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); # 初始化BootstrapRegistry
  8.         setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContext
  9.         setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); #
  10.         this.mainApplicationClass = deduceMainApplicationClass();
  11. }
复制代码
判断服务类型

WebApplicationType 是枚举类,有3种类型

  • NONE表现非web应用,不需要web服务器
  • SERVLET表现基于SERVLET的WEB应用,需要SERVLET服务器
  • REACTIVE表现响应式WEB应用,需要响应式web服务器
spring-mvc默认使用的Tomcat属于第二种,因此springApplication.webApplicationType = SERVLET,后续在refresh()方法里会启动Tomcat。
ClassUtils.isPresent调用Class.forName()方法查询类路径上是否存在某个类。
  1. public enum WebApplicationType {
  2.         NONE,
  3.         SERVLET,
  4.         REACTIVE;
  5.         private static final String[] SERVLET_INDICATOR_CLASSES = { "jakarta.servlet.Servlet",
  6.                         "org.springframework.web.context.ConfigurableWebApplicationContext" };
  7.         private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
  8.         private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
  9.         private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
  10.         static WebApplicationType deduceFromClasspath() {
  11.                 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
  12.                                 && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
  13.                         // 如果JVM无法加载WEBMVC_INDICATOR_CLASS类和JERSEY_INDICATOR_CLASS
  14.                         // 但是JVM可以加载WEBFLUX_INDICATOR_CLASS,则为响应式web
  15.                         return WebApplicationType.REACTIVE;
  16.                 }
  17.                 // 只要没有SERVLET_INDICATOR_CLASSES 中任意一个类,都属于非WEB服务
  18.                 for (String className : SERVLET_INDICATOR_CLASSES) {
  19.                         if (!ClassUtils.isPresent(className, null)) {
  20.                                 return WebApplicationType.NONE;
  21.                         }
  22.                 }
  23.                 // 同时包含SERVLET_INDICATOR_CLASSES的所有类,属于SERVELT web服务
  24.                 return WebApplicationType.SERVLET;
  25.         }
  26. }
复制代码
getSpringFactoriesInstances

  1. private <T> List<T> getSpringFactoriesInstances(Class<T> type) {
  2.         return getSpringFactoriesInstances(type, null);
  3. }
  4. private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {
  5.         return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
  6. }
  7. public static SpringFactoriesLoader forDefaultResourceLocation(@Nullable ClassLoader classLoader) {
  8.         return forResourceLocation(FACTORIES_RESOURCE_LOCATION, classLoader);
  9. }
复制代码
getSpringFactoriesInstances方法分2步.第一步加载工厂类SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()),DefaultResourceLocation就是"META-INF/spring.factories".第二步实例化工厂类load(type, argumentResolver)。
加载工厂类

  1. public class SpringFactoriesLoader {
  2.         public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  3.         static final Map<ClassLoader, Map<String, SpringFactoriesLoader>> cache = new ConcurrentReferenceHashMap<>();
  4.         // 加载"META-INF/spring.factories"工厂类的类加载器
  5.         private final ClassLoader classLoader;
  6.         private final Map<String, List<String>> factories;
  7.         // 默认加载"META-INF/spring.factories"中的类
  8.         public static SpringFactoriesLoader forDefaultResourceLocation(@Nullable ClassLoader classLoader) {
  9.                 return forResourceLocation(FACTORIES_RESOURCE_LOCATION, classLoader);
  10.         }
  11. }
复制代码
SpringFactoriesLoader 是spring.factories工厂类文件的加载器。forDefaultResourceLocation静态方法表现默认从每个jar包的"META-INF/spring.factories"文件加载类。
forResourceLocation静态方法实现加载工厂类而且生存在SpringFactoriesLoader类对象的静态变量cache中,每次调用getSpringFactoriesInstances方法就不消重复加载"META-INF/spring.factories"。
  1. public static SpringFactoriesLoader forResourceLocation(String resourceLocation, @Nullable ClassLoader classLoader) {
  2.         Assert.hasText(resourceLocation, "'resourceLocation' must not be empty");
  3.         // 获得类加载器,用于加载类,是AppClassLoader系统类加载器
  4.         ClassLoader resourceClassLoader = (classLoader != null ? classLoader :
  5.                         SpringFactoriesLoader.class.getClassLoader());
  6.         // loaders是当前类加载器所加载的资源键值对,key是资源名称,是`META-INF/spring.factories`,value是SpringFactoriesLoader对象
  7.         // cache是类的静态变量,全局唯一
  8.         Map<String, SpringFactoriesLoader> loaders = cache.computeIfAbsent(
  9.                         resourceClassLoader, key -> new ConcurrentReferenceHashMap<>());
  10.         return loaders.computeIfAbsent(resourceLocation, key ->
  11.                         new SpringFactoriesLoader(classLoader, loadFactoriesResource(resourceClassLoader, resourceLocation)));
  12. }
复制代码
loadFactoriesResource实现用AppClassLoader加载"META-INF/spring.factories"。结合下图分析源码。
  1. protected static Map<String, List<String>> loadFactoriesResource(ClassLoader classLoader, String resourceLocation) {
  2.         Map<String, List<String>> result = new LinkedHashMap<>();
  3.         try {
  4.             // Enumeration不是枚举类,是迭代器类
  5.                 Enumeration<URL> urls = classLoader.getResources(resourceLocation);
  6.                 while (urls.hasMoreElements()) {
  7.                     // resource是`META-INF/spring.factories`文件的路径
  8.                         UrlResource resource = new UrlResource(urls.nextElement());
  9.                         // Properties类定义:`class Properties extends Hashtable<Object,Object>`
  10.                         // Properties类是线程安全的属性类,用键值对表示属性
  11.                         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  12.                         properties.forEach((name, value) -> {
  13.                                 // 将键值对的值用逗号分隔开,并且将其放入result的value
  14.                                 String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) value);
  15.                                 List<String> implementations = result.computeIfAbsent(((String) name).trim(),
  16.                                                 key -> new ArrayList<>(factoryImplementationNames.length));
  17.                                 Arrays.stream(factoryImplementationNames).map(String::trim).forEach(implementations::add);
  18.                         });
  19.                 }
  20.                 // 表示将result的value变成不可变list
  21.                 result.replaceAll(SpringFactoriesLoader::toDistinctUnmodifiableList);
  22.         }
  23.         catch (IOException ex) {
  24.                 throw new IllegalArgumentException("Unable to load factories from location [" + resourceLocation + "]", ex);
  25.         }
  26.         // 表示将result整个map变成不可变map
  27.         return Collections.unmodifiableMap(result);
  28. }
复制代码

图中的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参数获取实现类的全限定类名,之后实例化。
  1. public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver) {
  2.         return load(factoryType, argumentResolver, null);
  3. }
  4. public <T> List<T> load(Class<T> factoryType, @Nullable ArgumentResolver argumentResolver,
  5.         @Nullable FailureHandler failureHandler) {
  6.         Assert.notNull(factoryType, "'factoryType' must not be null");
  7.         // loadFactoryNames方法就是获取cache中保存的`factoryType`的实现类全限定类名
  8.         List<String> implementationNames = loadFactoryNames(factoryType);
  9.         logger.trace(LogMessage.format("Loaded [%s] names: %s", factoryType.getName(), implementationNames));
  10.         List<T> result = new ArrayList<>(implementationNames.size());
  11.         FailureHandler failureHandlerToUse = (failureHandler != null) ? failureHandler : THROWING_FAILURE_HANDLER;
  12.         for (String implementationName : implementationNames) {
  13.                 // 实例化对象
  14.                 T factory = instantiateFactory(implementationName, factoryType, argumentResolver, failureHandlerToUse);
  15.                 if (factory != null) {
  16.                         result.add(factory);
  17.                 }
  18.         }
  19.         AnnotationAwareOrderComparator.sort(result);
  20.         return result;
  21. }
复制代码
  1. protected <T> T instantiateFactory(String implementationName, Class<T> type,
  2.                         @Nullable ArgumentResolver argumentResolver, FailureHandler failureHandler) {
  3.                 try {
  4.                         // 在JVM中加载implementationName实现类
  5.                         Class<?> factoryImplementationClass = ClassUtils.forName(implementationName, this.classLoader);
  6.                         // 校验实现类是否是type的子类
  7.                         Assert.isTrue(type.isAssignableFrom(factoryImplementationClass), () ->
  8.                                         "Class [%s] is not assignable to factory type [%s]".formatted(implementationName, type.getName()));
  9.                         // FactoryInstantiator<T>获得`factoryImplementationClass`类的构造器对象`Constructor<T>`
  10.                         FactoryInstantiator<T> factoryInstantiator = FactoryInstantiator.forClass(factoryImplementationClass);
  11.                         // 调用构造器对象的`constructor.newInstance(args)`方法生成对象。
  12.                         return factoryInstantiator.instantiate(argumentResolver);
  13.                 }
  14.                 catch (Throwable ex) {
  15.                         failureHandler.handleFailure(type, implementationName, ex);
  16.                         return null;
  17.                 }
  18.         }
复制代码
初始化

  1.         this.bootstrapRegistryInitializers = new ArrayList<>(
  2.                         getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); # 初始化BootstrapRegistry
  3.         setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); # 初始化ApplicationContext
  4.         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 实现类,界说监听的事件。
  1. public class MyListener implements ApplicationListener<ApplicationEvent> {
  2.         // 当出现事件(`ApplicationEvent`的实现类),`onApplicationEvent`就会被执行。
  3.     @Override
  4.     public void onApplicationEvent(ApplicationEvent event) {
  5.         System.out.println("事件: " + event);
  6.     }
  7.     @Override
  8.     public boolean supportsAsyncExecution() {
  9.         return ApplicationListener.super.supportsAsyncExecution();
  10.     }
  11. }
复制代码
在META-INF/spring.factories加一org.springframework.context.ApplicationListener=com.example.demo.MyListener。
启动项目,加载的实现类中就包罗自界说的实现类。

deduceMainApplicationClass

推导主类。源码表现:在(栈帧StackWalker对象)中找到第一个名称为main的方法,该方法所在的类就是主类。
  1. private Class<?> deduceMainApplicationClass() {
  2.         return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
  3.                 .walk(this::findMainClass)
  4.                 .orElse(null);
  5. }
  6. private Optional<Class<?>> findMainClass(Stream<StackFrame> stack) {
  7.         return stack.filter((frame) -> Objects.equals(frame.getMethodName(), "main"))
  8.                 .findFirst()
  9.                 .map(StackWalker.StackFrame::getDeclaringClass);
  10. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表