拉不拉稀肚拉稀 发表于 2024-12-22 19:38:23

SpringBoot 启动类 SpringApplication 一 构造器方法

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);
}
https://i-blog.csdnimg.cn/direct/ed0701d56f1f4d0092ffebc8b0154005.png
图中的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个初始化器。
https://i-blog.csdnimg.cn/direct/7d9d8fed0f2a431aa92dc22d18734fde.png
监听器

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。
启动项目,加载的实现类中就包罗自界说的实现类。
https://i-blog.csdnimg.cn/direct/513ae3ae57284ca4af015bdda14c5c27.png
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企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: SpringBoot 启动类 SpringApplication 一 构造器方法