美文网首页java基础SpringBoot
springboot源码----SpringApplicatio

springboot源码----SpringApplicatio

作者: 堵金凯 | 来源:发表于2018-08-24 17:18 被阅读0次

    SpringApplicationRunListener 接口的作用主要就是在springboot 启动初始化的过程中可以通过SpringApplicationRunListener接口回调来让用户在启动的各个流程中可以加入自己的逻辑

        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();
    

    在run方法中springboot 通过getRunListeners方法获得SpringApplicationRunListener接口全部的实现类

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

    初始化方法和之前一样 也是通过读取spring.factories文件通过反射的机制获取实现类
    接下来看下SpringApplicationRunListener接口的定义:

    public interface SpringApplicationRunListener {
    
        /**
         * Called immediately when the run method has first started. Can be used for very
         * early initialization.
         */
        void starting();
    
        /**
         * Called once the environment has been prepared, but before the
         * {@link ApplicationContext} has been created.
         * @param environment the environment
         */
        void environmentPrepared(ConfigurableEnvironment environment);
    
        /**
         * Called once the {@link ApplicationContext} has been created and prepared, but
         * before sources have been loaded.
         * @param context the application context
         */
        void contextPrepared(ConfigurableApplicationContext context);
    
        /**
         * Called once the application context has been loaded but before it has been
         * refreshed.
         * @param context the application context
         */
        void contextLoaded(ConfigurableApplicationContext context);
    
        /**
         * The context has been refreshed and the application has started but
         * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
         * ApplicationRunners} have not been called.
         * @param context the application context.
         * @since 2.0.0
         */
        void started(ConfigurableApplicationContext context);
    
        /**
         * Called immediately before the run method finishes, when the application context has
         * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
         * {@link ApplicationRunner ApplicationRunners} have been called.
         * @param context the application context.
         * @since 2.0.0
         */
        void running(ConfigurableApplicationContext context);
    
        /**
         * Called when a failure occurs when running the application.
         * @param context the application context or {@code null} if a failure occurred before
         * the context was created
         * @param exception the failure
         * @since 2.0.0
         */
        void failed(ConfigurableApplicationContext context, Throwable exception);
    
    }
    
    • 第一个方法 starting触发时机:
        StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
    

    这边主要看listeners.starting()

        public void starting() {
            for (SpringApplicationRunListener listener : this.listeners) {
                listener.starting();
            }
        }
    

    这边在spring刚拿到所有的SpringApplicationRunListener实现类后就直接调用了starting 通知各个SpringApplicationRunListener的实现类

    • 第二个environmentPrepared触发时间:
    private ConfigurableEnvironment prepareEnvironment(
                SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments) {
            // Create and configure the environment
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            configureEnvironment(environment, applicationArguments.getSourceArgs());
            listeners.environmentPrepared(environment);
            bindToSpringApplication(environment);
            if (this.webApplicationType == WebApplicationType.NONE) {
                environment = new EnvironmentConverter(getClassLoader())
                        .convertToStandardEnvironmentIfNecessary(environment);
            }
            ConfigurationPropertySources.attach(environment);
            return environment;
        }
    

    在准备好了ConfigurableEnvironment坏境的时候通知各个实现类

    • 第三个contextPrepared触发时间:
        private void prepareContext(ConfigurableApplicationContext context,
                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
            postProcessApplicationContext(context);
            applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                logStartupInfo(context.getParent() == null);
                logStartupProfileInfo(context);
            }
    

    在spring 结束applyInitializers后进行通知

    • 第四个 contextLoaded 触发时间
        private void prepareContext(ConfigurableApplicationContext context,
                ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
            postProcessApplicationContext(context);
            applyInitializers(context);
            listeners.contextPrepared(context);
            if (this.logStartupInfo) {
                logStartupInfo(context.getParent() == null);
                logStartupProfileInfo(context);
            }
    
            // Add boot specific singleton beans
            context.getBeanFactory().registerSingleton("springApplicationArguments",
                    applicationArguments);
            if (printedBanner != null) {
                context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
            }
    
            // Load the sources
            Set<Object> sources = getAllSources();
            Assert.notEmpty(sources, "Sources must not be empty");
            load(context, sources.toArray(new Object[0]));
            listeners.contextLoaded(context);
        }
    

    在加载完资源类(启动类)后进行通知

    • 第五个 started
                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);
    

    在所有的bean 都初始化后 进行触发

    • 第六个 running
            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);
            }
    

    在调用完所有的ApplicationRunner和CommandLineRunner实现类后调用

    第七个 failed
    在启动失败的时候通知

    自定义SpringApplicationRunListener

    实现SpringApplicationRunListener接口

    
    /**
     * Created by dujinkai on 2018/8/14.
     */
    public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    
        public MySpringApplicationRunListener(SpringApplication application, String[] args) {
        }
        @Override
        public void starting() {
            System.out.println("starting");
        }
    
        @Override
        public void environmentPrepared(ConfigurableEnvironment configurableEnvironment) {
            System.out.println("environmentPrepared");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext configurableApplicationContext) {
            System.out.println("contextPrepared");
    
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext configurableApplicationContext) {
            System.out.println("contextLoaded");
        }
    
        @Override
        public void started(ConfigurableApplicationContext configurableApplicationContext) {
            System.out.println("started");
        }
    
        @Override
        public void running(ConfigurableApplicationContext configurableApplicationContext) {
    
            System.out.println("running");
        }
    
        @Override
        public void failed(ConfigurableApplicationContext configurableApplicationContext, Throwable throwable) {
            System.out.println("failed");
    
        }
    }
    

    然后把该类放入spring.factories文件中,这种方式就是在run方法里面会进行初始化这个监听,当使用这种方法的时候必须要注意必须提供一个有2个参数的有参构造器 SpringApplication 和String[] 原因是:

    
        private SpringApplicationRunListeners getRunListeners(String[] args) {
            Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
            return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                    SpringApplicationRunListener.class, types, this, args));
        }
    
        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;
        }
    
        @SuppressWarnings("unchecked")
        private <T> List<T> createSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
                Set<String> names) {
            List<T> instances = new ArrayList<>(names.size());
            for (String name : names) {
                try {
                    Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                    Assert.isAssignable(type, instanceClass);
                    Constructor<?> constructor = instanceClass
                            .getDeclaredConstructor(parameterTypes);
                    T instance = (T) BeanUtils.instantiateClass(constructor, args);
                    instances.add(instance);
                }
                catch (Throwable ex) {
                    throw new IllegalArgumentException(
                            "Cannot instantiate " + type + " : " + name, ex);
                }
            }
            return instances;
        }
    

    从源码的 Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    可以看出 利用反射生成对象的时候必须要带有这2个参数。

    相关文章

      网友评论

        本文标题:springboot源码----SpringApplicatio

        本文链接:https://www.haomeiwen.com/subject/ozhiiftx.html