spring boot 2.0 源码分析(二)

  • 时间:
  • 浏览:3
  • 来源:大发uu快3_uu快3开奖历史_大发uu快3开奖历史

在上一章学习了spring boot 2.0启动的要花费流程之前 ,今天亲戚大伙儿 来深挖一下SpringApplication实例变量的run函数。

先把这段run函数的代码贴出来:

    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

亲戚大伙儿 先来分析其中的第俩个多 关键代码:SpringApplicationRunListeners listeners = getRunListeners(args);

这行代码是获取监听器,亲戚大伙儿 先跳转到getRunListeners中看一下:

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }

在这段代码中,亲戚大伙儿 看多获取监听器,是new出来了俩个多 SpringApplicationRunListeners实例并返回。

再次跳转到SpringApplicationRunListeners的构造函数中,看多一架构设计 生了什么:

    SpringApplicationRunListeners(Log log, 
    Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList(listeners);
    }

在这一 构造函数里,亲戚大伙儿 看多其为何让把接收到的listeners参数,保存到实例变量里,没法过多的操作。

也不我,重点是在listeners参数这里,而listeners是通过getSpringFactoriesInstances创建出来的,来看一下getSpringFactoriesInstances函数做了什么事情吧:

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(
                SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
                classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

在这里亲戚大伙儿 看多,首先创建了俩个多 classloader,为何让用SpringFactoriesLoader.loadFactoryNames(type, classLoader),加载了SpringFactoriesLoader列表。亲戚大伙儿 来看一下loadFactoryNames后边的代码:

    public static List<String> loadFactoryNames(Class<?> factoryClass,
     @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, 
        Collections.emptyList());
    }
    
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap result = (MultiValueMap)cache.get(classLoader);
        if(result != null) {
            return result;
        } else {
            try {
                Enumeration ex = classLoader != null?
                classLoader.getResources("META-INF/spring.factories")
                :ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result1 = new LinkedMultiValueMap();

                while(ex.hasMoreElements()) {
                    URL url = (URL)ex.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry entry = (Entry)var6.next();
                        List factoryClassNames = Arrays.asList(StringUtils
                        .commaDelimitedListToStringArray((String)entry.getValue()));
                        result1.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }

                cache.put(classLoader, result1);
                return result1;
            } catch (IOException var9) {
                throw new IllegalArgumentException(
                "Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }

通过这里亲戚大伙儿 看多了其首先加载了META-INF/spring.factories这一 配置文件下的所有资源,并装在去缓存,为何让再获取了org.springframework.context.ApplicationListener定义的资源列表。

小发现:在这里亲戚大伙儿 发现spring boot自动装配文件的位置。

获取到META-INF/spring.factories这一 配置文件下的资源名称列表之前 ,通过createSpringFactoriesInstances函数创建了SpringFactories的实例。

    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, 
    ClassLoader classLoader, Object[] args, Set<String> names) {
        ArrayList instances = new ArrayList(names.size());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                Class ex = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, ex);
                Constructor constructor = ex.getDeclaredConstructor(parameterTypes);
                Object instance = BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name,
                 var12);
            }
        }

        return instances;
    }

通之前 边的什么代码流转,亲戚大伙儿 要花费搞清楚了listeners是为何创建出来的。

为何让调用了listeners的starting法律法律依据 。亲戚大伙儿 先要花费地看一下EventPublishingRunListener后边的starting的实现:

    public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application,
         this.args));
    }

关键代码在这里:

    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if(executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                this.invokeListener(listener, event);
            }
        }

    }

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if(errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }

    }

在后边代码中亲戚大伙儿 看多,starting为何让拿到META-INF/spring.factories中定义的资源的实例之前 ,为何让再创建俩个多 tcp连接池去启动起来。

通之前 边的什么代码亲戚大伙儿 知道了spring boot会获取META-INF/spring.factories中的资源,并创建什么资源的实例(listeners监听器),为何让为每俩个多 监听器创建俩个多 tcp连接池启动起来。

篇幅有限, 今天就写到这里吧。有希望一块儿学习spring boot 2.0源码的同学能不需要 关注我,跟我一块儿分析spring boot 2.0 源码的实现法律法律依据 。

猜你喜欢

學好中文 人生贏家敲門磚

圖:蘇發努馮大學孔子學院在老撾第二大城市琅勃拉邦,有一座僅次於國立大學的高校:蘇發努馮大學。從校門進入繞過寬大的草坪就能就看「孔子學院」的指示牌,院長張明虎(左圖)說雖然他們才

2020-01-20

Antonio Montiel数据,Antonio Montiel新闻,Antonio Montiel视频,Antonio Montiel身价

首页新闻视频直播数据APP懂球号直播君广告合作协议方式AntonioMontielAntonioMontiel俱乐部:国籍:西班牙身高:184CM位置:球员年龄:29岁体重:7

2020-01-20

暗示防长要下台?特朗普:马蒂斯“像民主党人”

美国防部长詹姆斯·马蒂斯。(图源:美联社)美国总统唐纳德·特朗普在当地时间周日(14日)曝光的一段公开采访片段中表示,国防部长詹姆斯·马蒂斯(JamesMattis)“一阵一阵

2020-01-20

阿姆利奥VS贝里奥免费视频直播,阿姆利奥VS贝里奥比赛集锦,阿姆利奥VS贝里奥录像,阿姆利奥VS贝里奥首发阵容

首页新闻视频直播数据APP懂球号直播君广告公司合作 阿姆利奥05-0600:00西丙2-5已始于贝里奥直播君|分析|集锦暂无数据近期比赛萨索洛意甲2-1都灵纽卡斯尔联英超1-

2020-01-20

欧迪兹亚VS德乌斯托免费视频直播,欧迪兹亚VS德乌斯托比赛集锦,欧迪兹亚VS德乌斯托录像,欧迪兹亚VS德乌斯托首发阵容

首页新闻视频直播数据APP懂球号直播君广告商务战略合作欧迪兹亚05-0523:00西丙1-2已开始德乌斯托直播君|分析|集锦暂无数据近期比赛萨索洛意甲2-1都灵纽卡斯尔联英超1

2020-01-20