spring boot 源码解析3-SpringApplication#run

前言

在spring boot 源码解析2-SpringApplication初始化 中我们分析了SpringApplication的初始化.接下来我们继续分析SpringApplication的run方法.

解析

  1. SpringApplication#run方法的代码如下:

    public ConfigurableApplicationContext run(String... args) {
        // 计时工具
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            // 创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            Banner printedBanner = printBanner(environment);
            // 创建SpringBoot上下文
            context = createApplicationContext();
            analyzers = new FailureAnalyzers(context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            listeners.finished(context, null);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            return context;
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, analyzers, ex);
            throw new IllegalStateException(ex);
        }
    }
    

    该方法做了13件事:

    1. 初始化StopWatch,调用其start方法开始计时.

    2. 调用configureHeadlessProperty设置系统属性java.awt.headless,这里设置为true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能

    3. 调用SpringApplicationRunListeners#starting

    4. 创建一个DefaultApplicationArguments对象,它持有着args参数,就是main函数传进来的参数.调用prepareEnvironment方法.

    5. 打印banner

    6. 创建SpringBoot上下文

    7. 初始化FailureAnalyzers

    8. 调用prepareContext

    9. 调用AbstractApplicationContext#refresh方法,并注册钩子

    10. 在容器完成刷新后,依次调用注册的Runners

    11. 调用SpringApplicationRunListeners#finished

    12. 停止计时

    13. 初始化过程中出现异常时调用handleRunFailure进行处理,然后抛出IllegalStateException异常.

  2. run方法中第1步.代码如下:

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    在StopWatch初始化时,设置id为”“.代码如下:

    public StopWatch() {
        this("");
    }
    
    public StopWatch(String id) {
        this.id = id;
    }

    start方法代码如下:

    public void start() throws IllegalStateException {
        start("");
    }
    
    public void start(String taskName) throws IllegalStateException {
        if (this.running) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        }
        this.running = true;
        this.currentTaskName = taskName;
        this.startTimeMillis = System.currentTimeMillis();
    }

    在start方法中,首先判断当前状态是否为running.如果是的话,抛出异常.如果不是的话,将running设置为true.currentTaskName设置为”“,startTimeMillis为当前时间.

    在run方法中的第12步中,调用了StopWatch#stop方法.停止计时.代码如下:

    public void stop() throws IllegalStateException {
        if (!this.running) {
            throw new IllegalStateException("Can't stop StopWatch: it's not running");
        }
        long lastTime = System.currentTimeMillis() - this.startTimeMillis;
        this.totalTimeMillis += lastTime;
        this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
        if (this.keepTaskList) {
            this.taskList.add(lastTaskInfo);
        }
        ++this.taskCount;
        this.running = false;
        this.currentTaskName = null;
    }
    

    还是同样的套路.如果running为false –> 抛出异常.如果不是.则计算得出lastTime.初始化TaskInfo.将TaskInfo加入到taskList中.增加taskCount计数器.将running设为false,将currentTaskName置为null.

  3. run方法第2步–> 调用configureHeadlessProperty方法.设置系统属性java.awt.headless,这里设置为true,表示运行在服务器端,在没有显示器和鼠标键盘的模式下工作,模拟输入输出设备功能.该方法如下:

    private void configureHeadlessProperty() {
        System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
                SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
    }
  4. run方法第3步,代码如下:

    SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();

    getRunListeners方法如下:

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

    还是同样的味道.通过调用getSpringFactoriesInstances加载SpringApplicationRunListener.然后初始化SpringApplicationRunListeners.

    对应当前场景来说,org.springframework.boot.SpringApplicationRunListener只有一个.如下:

    org.springframework.boot.SpringApplicationRunListener=\
    org.springframework.boot.context.event.EventPublishingRunListener

    在初始化EventPublishingRunListener时,会将SpringApplication中的Listeners添加到EventPublishingRunListener中的initialMulticaster.代码如下:

    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }

    然后调用SpringApplicationRunListeners#starting方法.代码如下:

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

    由于只有一个,因此会调用EventPublishingRunListener的starting方法.代码如下:

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

    接着调用SimpleApplicationEventMulticaster#multicastEvent.代码如下:

    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    调用

    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            else {
                invokeListener(listener, event);
            }
        }
    }

    该方法调用getApplicationListeners获得ApplicationListener.然后调用SimpleApplicationEventMulticaster#invokeListener方法.

    getApplicationListeners代码如下:

    protected Collection<ApplicationListener<?>> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {
    
        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        // 1. 构造ListenerCacheKey
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    
        // Quick check for existing entry on ConcurrentHashMap...
        // 2. 如果retrieverCache中有的话,直接返回
        ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        }
    
        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            // Fully synchronized building and caching of a ListenerRetriever
            synchronized (this.retrievalMutex) {
                retriever = this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                }
                retriever = new ListenerRetriever(true);
                Collection<ApplicationListener<?>> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            // No ListenerRetriever caching -> no synchronization necessary
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }

    该方法首先构建ListenerCacheKey,然后查询缓存中是否有的话,直接返回.否则调用retrieveApplicationListeners方法.如果

    this.beanClassLoader == null ||
    (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
    (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) 为真的话,则调用retrieveApplicationListeners方法时会进行加锁.并将方法的返回值加入缓存.一般都会放入缓存的.

    retrieveApplicationListeners方法,代码如下:

    private Collection<ApplicationListener<?>> retrieveApplicationListeners(
            ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) {
    
        LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
        Set<ApplicationListener<?>> listeners;
        Set<String> listenerBeans;
        synchronized (this.retrievalMutex) {
            listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
        }
        for (ApplicationListener<?> listener : listeners) {
            if (supportsEvent(listener, eventType, sourceType)) {
                if (retriever != null) {
                    retriever.applicationListeners.add(listener);
                }
                allListeners.add(listener);
            }
        }
        if (!listenerBeans.isEmpty()) {
            BeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : listenerBeans) {
                try {
                    Class<?> listenerType = beanFactory.getType(listenerBeanName);
                    if (listenerType == null || supportsEvent(listenerType, eventType)) {
                        ApplicationListener<?> listener =
                                beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                        if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                            if (retriever != null) {
                                retriever.applicationListenerBeans.add(listenerBeanName);
                            }
                            allListeners.add(listener);
                        }
                    }
                }
                catch (NoSuchBeanDefinitionException ex) {
                    // Singleton listener instance (without backing bean definition) disappeared -
                    // probably in the middle of the destruction phase
                }
            }
        }
        AnnotationAwareOrderComparator.sort(allListeners);
        return allListeners;
    }

    处理逻辑如下:

    1. 初始化allListeners, listeners,listenerBeans,对于当前场景来说. listeners 中的元素如下:

      org.springframework.boot.context.config.ConfigFileApplicationListener, 
      org.springframework.boot.context.config.AnsiOutputApplicationListener, 
      org.springframework.boot.logging.LoggingApplicationListener, 
      org.springframework.boot.logging.ClasspathLoggingApplicationListener, 
      org.springframework.boot.autoconfigure.BackgroundPreinitializer, 
      org.springframework.boot.context.config.DelegatingApplicationListener, 
      org.springframework.boot.builder.ParentContextCloserApplicationListener, 
      org.springframework.boot.ClearCachesApplicationListener, 
      org.springframework.boot.context.FileEncodingApplicationListener, 
      org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

      listenerBeans中的元素为空.

    2. 遍历listeners, listenerBeans 如果监听器是否支持指定的事件则加入到allListeners.

    3. 排序

    对于当前场景ApplicationStartedEvent支持的listeners如下:

    org.springframework.boot.logging.LoggingApplicationListener, 
    org.springframework.boot.autoconfigure.BackgroundPreinitializer, 
    org.springframework.boot.context.config.DelegatingApplicationListener, 
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

    SimpleApplicationEventMulticaster#invokeListener方法如下:

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

    该方法主要调用doInvokeListener,当ErrorHandler不为null时,当调用doInvokeListener出现异常时,会交由ErrorHandler进行处理.对于当前, ErrorHandler为null,那么ErrorHandler什么时候进行设置呢?如下:

    ErrorHandler设置调用链

    doInvokeListener代码如下:

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || msg.startsWith(event.getClass().getName())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                Log logger = LogFactory.getLog(getClass());
                if (logger.isDebugEnabled()) {
                    logger.debug("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

    对于LoggingApplicationListener,会调用LoggingApplicationListener#onApplicationStartingEvent方法.代码如下:

    private void onApplicationStartingEvent(ApplicationStartingEvent event) {
        this.loggingSystem = LoggingSystem
                .get(event.getSpringApplication().getClassLoader());
        this.loggingSystem.beforeInitialize();
    }

    对于当前场景来说,loggingSystem为LogbackLoggingSystem.

    对于BackgroundPreinitializer,DelegatingApplicationListener来说,没有做任何事.

    对于LiquibaseServiceLocatorApplicationListener,代码如下:

    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        if (ClassUtils.isPresent("liquibase.servicelocator.ServiceLocator", null)) {
            new LiquibasePresent().replaceServiceLocator();
        }
    }

    对于场景来说,在项目的类路径下,不存在liquibase.servicelocator.ServiceLocator.

    本文就到这里.剩下的后续分析.

引用: "ERROR org.springframework.boot.SpringApplication - Application run failed.yaml.snakeyaml.reader.ReaderException: special characters are not allowed" 这个错误信息说明在应用程序运行时出现了问题,具体是由于在YAML文件中使用了不允许的特殊字符导致的。特殊字符在YAML中通常是不被允许的,因为它们可能引发解析错误。需要检查YAML文件中是否存在特殊字符,并根据具体情况进行修改。 引用: "3.将数据库脚本导入到MySQL数据库服务器,在common\config下找到main-local.php修改数据库配置信息,‘dsn’为数据连接字符串,其中host为数据库地址,port为连接端口,dbname为数据库名称;‘username’为数据库..." 这个引用提到了将数据库脚本导入到MySQL数据库服务器,并修改数据库配置信息的步骤。在common\config文件夹下的main-local.php文件中,可以找到数据库的连接字符串和其他配置信息,例如数据库地址、连接端口、数据库名称以及数据库用户名等。根据需要,您可以修改这些配置信息以适应您的环境。 综上所述,出现"ERROR org.springframework.boot.SpringApplication - Application run failed"错误可能是由于YAML文件中使用了不允许的特殊字符导致的。您可以检查YAML文件并修改其中的特殊字符。另外,在修改数据库配置信息时,请确保按照提供的步骤将数据库脚本导入到MySQL数据库服务器,并在main-local.php文件中正确配置数据库连接字符串和其他相关信息。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [ERROR org.springframework.boot.SpringApplication - Application run failed org.yaml.snakeyaml.reader](https://blog.csdn.net/qq_47291002/article/details/129685984)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [富盈国际微盘源码点位盘yii高端系列,包含原油期货盘,直播页面和完整运营版,内附安装说明](https://download.csdn.net/download/weixin_36643308/88251229)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值