专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

SpringBoot 之 SpringApplication

springboot版本 2.1.1

SpringApplication 实例化做了什么?

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 加载器,一般是null
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //一般是springboot启动类
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //判断web环境是servlet还是reactive还是none 
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //获取所有springboot项目下面下的META-INF/spring.factories的ApplicationContextInitializer
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection)
        //获取所有springboot项目下面下的META-INF/spring.factories 的ApplicationListener
        getSpringFactoriesInstances(ApplicationListener.class));
        //这个做法有点意思,springboot创建一个异常,通过异常的堆栈拿到执行main方法的类
        this.mainApplicationClass = deduceMainApplicationClass();
    }

上面大概讲了springboot实例化做的事情,接下来细化下

怎么判断当前web环境是servlet还是reactive还是none

现在的web项目一般都是基于servlet,这是spring5的新特性之一:reactive是不依赖servlet,大概看了下reactive相关的包结构基本于springmvc差不多,但是没细看怎么做到不依赖servlet

WebApplicationType.deduceFromClasspath

static WebApplicationType deduceFromClasspath() {
        //如果项目中有orgspringframework.web.reactive.DispatcherHandler的类
        //而且没有org.glassfish.jersey.servlet.ServletContainer 和
        //org.springframework.web.servlet.DispatcherServlet 那就当作当前web环境是reactive环境
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        // "javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext只要有一个类不存在就当作none,不是web项目
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        //web环境是servlet
        return WebApplicationType.SERVLET;
    }

总结就是判断reactive和servlet相关的类有没有在项目中依赖

获取所有springboot项目下面下的META-INF/spring.factories的ApplicationContextInitializer
        //springboot初始化的代码
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
            //获取类加载器
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        //这个重要,去加载spring.factories
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
                //通过spring.factories获取到的全类名实例化对象
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
                //排序
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

怎么加载spring.factories

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { //MultiValueMap 就是一个map,先从缓存中获取 MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { //加载META-INF/spring.factories 中的数据,可能存在多个Spring.factories //在扩展spring的时候也可以自己在META-INF 下面添加spring.factories Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); //这个是一个spring自定义的map但是没有具体的时候,因为其实里面是用一个Map<string,List>(这个list是LinkedList)来接 result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); //用逗号分隔成多个(好像还有换行符) for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } } //放到缓存中 cache.put(classLoader, result); return result; } }

所以就是通过加载spring.factories得到key接口,value是实现类,同时放到缓存中,可以用来做spring扩展

    //实例化  ApplicationContextInitializer 之后放到这个list
    private List<ApplicationContextInitializer<?>> initializers;
    //实例化  ApplicationListener 之后放到这个list
    private List<ApplicationListener<?>> listeners;

上面就是springboot大概的实例化

run方法做了什么?

public ConfigurableApplicationContext run(String... args) {
        .....
        //获取监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //执行监听器
        listeners.starting();
        .......
}

getRunListeners(args) 这个方法做了什么

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        //从spring.factories 取出 SpringApplicationRunListener
        目前只有 EventPublishingRunListener (其实并不是真实的监听器,往下看)
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }

listeners.starting() 其实是调用了EventPublishingRunListener#starting

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        //EventPublishingRunListener实例化的时候,会创建一个广播器,然并且往广播//器放真实的监听,这些监听都是SpringApplicaition实例化的时候从spring.fac//tories拿出来的,后面需要通知监听器的时候就是使用广播器通知
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

        public void starting() {
        //直接调用广播器
        this.initialMulticaster.multicastEvent(
                new ApplicationStartingEvent(this.application, this.args));
    }

接下来看下 SimpleApplicationEventMulticaster#multicastEvent

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //通过 getApplicationListeners 获取符合条件的监听器
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
            //执行监听器的 onApplicationEvent 方法
                invokeListener(listener, event);
            }
        }
    }

getApplicationListeners 获取符合条件的监听器其实就是调用GenericApplicationListener#supportsEventType 来判断的,所以一般写spring监听器,就是实现 GenericApplicationListener#supportsEventType方法,来判断自己的监听对什么事件感兴趣

未完待续……….

文章永久链接:https://tech.souyunku.com/26713

未经允许不得转载:搜云库技术团队 » SpringBoot 之 SpringApplication

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们