前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot之SpringApplication Explain

SpringBoot之SpringApplication Explain

作者头像
Isaac Zhang
发布2019-09-10 17:55:12
6230
发布2019-09-10 17:55:12
举报
文章被收录于专栏:奔跑的人生奔跑的人生

SpringApplication Explain

The SpringApplication class provides a convenient way to bootstrap a Spring application that is started from a main() method. In many situations, you can delegate to the static SpringApplication.run method, as shown in the following example. (SpringApplication类提供了一种便利的方式以便引导Spring应用从#main启动,大多数情况下,可以通过静态方法SpringApplication#run代理启动)

How TO Use SpringApplication

代码语言:javascript
复制
@EnableAutoConfiguration
public class MyApplication  {
    // ... Bean definitions
    public static void main(String[] args) throws Exception {
      SpringApplication.run(MyApplication.class, args);
    }
 }

Customize SpringApplication

UseSpringApplicationAPI To Change

代码语言:javascript
复制
public static void main(String[] args) {
    SpringApplication app = new SpringApplication(MySpringConfiguration.class);
    app.setBannerMode(Banner.Mode.OFF);
    app.run(args);
}

UseSpringApplicationBuilder API To Change

代码语言:javascript
复制
new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);

SpringApplication Preparing Stage

Configure Spring Boot Bean's Sources

Java 配置类或XML上下文配置集合,用于Spring Boot BeanDefinitionLoader读取,并且将配置源解析加载为Spring Bean 定义。

  • 数量,一个或者多个
Java Configuration Class

使用Spring 注解驱动中的Java配置类,也就是Spring 模式注解所标注的类,例如@Configuration

代码语言:javascript
复制
package com.yi23.backend.springboot.bootstrap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * {@link SpringApplication} 启动引导类
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
 * @see
 * @since
 */
@SpringBootApplication
public class SpringApplicationBootstrap {

    public static void main(String[] args) {
        SpringApplication.run(SpringApplicationBootstrap.class,args);
    }
}
XML Configure

用户Spring 传统配置驱动的XML文件

代码语言:javascript
复制
...
        //设置Annotation配置源
        Set<String> sources = new HashSet<>();
        //A source can be: a class name, package name, or an XML resource location.
        sources.add(Yi23ApplicationConfiguration.class.getName());
        springApplication.setSources(sources);
...

Deduce Web Application Type

根据当前应用CLassPath中是否存在相关实现来推断Web Application Type,包括:

  • Web Reactive : WebApplicationType.REACTIVE
  • Web Servlet : WebApplicationType.SERVLET
  • 非Web : WebApplicationType.NONE

参考:org.springframework.boot.SpringApplication#deduceWebApplicationType

代码语言:javascript
复制
private WebApplicationType deduceWebApplicationType() {
        if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
                && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        for (String className : WEB_ENVIRONMENT_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }
  • 版本意识,下图为Spring Boot 2.1.3中的推断实现

Deduce Main Class

跟住main线程的执行堆栈判断当前实际的引导类

参考:org.springframework.boot.SpringApplication#deduceMainApplicationClass

代码语言:javascript
复制
private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

Load ApplicationContextInitializer

ApplicationContextInitializer是应用上下文的加载器,利用Spring 工厂加载机制,实例化ApplicationContextInitializer实现类,并实现对象集合排序

  • 代码
代码语言:javascript
复制
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;
    }
  • 实现技术
    • 实现类:org.springframework.core.io.support.SpringFactoriesLoader
    • 配置文件:META-INF/spring.factories
    • 排序:org.springframework.core.annotation.AnnotationAwareOrderComparator#sort
代码语言:javascript
复制
package com.yi23.backend.springboot.context;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * 自定义高优先级{@link ApplicationContextInitializer}初始化加载器
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
 * @see
 * @since
 */
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloYi23ApplicationContextInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("高优先级初始化加载class : "
                + applicationContext.getId());
    }
}
代码语言:javascript
复制
# Initializers
org.springframework.context.ApplicationContextInitializer=\
com.yi23.backend.springboot.context.AfterHelloYi23ApplicationContextInitializer,\
com.yi23.backend.springboot.context.HelloYi23ApplicationContextInitializer

Load ApplicationListener

利用Spring 工厂加载机制,实例化ApplicationLisener实现类,并实现对象集合排序

代码语言:javascript
复制
package com.yi23.backend.springboot.event.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
/**
 * hello yi23 {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}事件
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
 * @see
 * @since
 */
public class HelloYi23ApplicationListener
        implements ApplicationListener<ContextRefreshedEvent>,Ordered {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.printf("上下文内容id:%s,timestamp:%s.\r\n",
                event.getApplicationContext().getId(), event.getTimestamp());
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

SpringApplication Running Stage

Load SpringApplication Run Listener

org.springframework.boot.SpringApplicationRunListeners

利用工厂加载机制,读取SpringApplicationRunListener对象集合,并封装到组合对象SpringApplicationRunListeners

代码语言:javascript
复制
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }

Running SpringApplication Run Listeners

SpringApplicationRunListener 监听多个运行状态方法

监听方法

阶段说明

Springboot 起始版本

starting

Spring 应用刚刚启动

1.0

environmentPrepared(ConfigurableEnvironment)

ConfigurableEnvironment准确之后,允许将其修改

1.0

contextPrepared(ConfigurableApplicationContext)

ConfigurableApplicationContext准备之后,允许将其修改

1.0

contextLoaded(ConfigurableApplicationContext)

ConfigurableApplicationContext已加载,但未启动

1.0

started(ConfigurableApplicationContext)

ConfigurableApplicationContext已启动,当前Spring Bean已初始化完成

2.0.0

running(ConfigurableApplicationContext)

Spring Application 正在运行

2.0.0

failed(ConfigurableApplicationContex,Throwable)

Spring Application运行失败

2.0.0

Monitor Spring-Boot Event / Spring Event

SpringBoot 通过SpringApplicationRunListener的实现类EventPublishingRunListener,利用Spring Framework事件API,广播Spring Boot 事件

Spring Framework Event/Listener Model
  • Spring 应用事件
    • 普通应用事件:ApplicationEvent
    • 应用上下文事件:ApplicationContextEvent
  • Spring 应用监听器
    • 接口编程模型:ApplicationListener
    • 注解编程模型:@EventListener
  • Spring 应用事件广播器
    • 接口:ApplicationEventMulticaster
    • 实现类:SimpleApplicationEventMulticaster
      • 执行模式:同步/异步
EventPublishingRunListener relationship of Monitor‘s Method & Spring Boot Events

监听方法

Spring Boot 事件

Spring boot 起始版本

starting

ApplicationStartingEvent

1.5.0

environmentPrepared(ConfigurableEnvironment)

ApplicationEnvironmentPreparedEvent

1.0

contextPrepared(ConfigurableApplicationContext)

contextLoaded(ConfigurableApplicationContext)

ApplicationPreparedEvent

1.0

started(ConfigurableApplicationContext)

ApplicationStartedEvent

2.0.0

running(ConfigurableApplicationContext)

ApplicationReadyEvent

1.3.0

failed(ConfigurableApplicationContex,Throwable)

ApplicationFailedEvent

1.0

Validate ConfigFileApplicationListener Order
代码语言:javascript
复制
package com.yi23.backend.springboot.event.listener;

import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;

/**
 * Before {@link ConfigFileApplicationListener}
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
 * @see
 * @since
 */
public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {

    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
        return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
                || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    @Override
    public boolean supportsSourceType(Class<?> aClass) {
        return true;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent) event;
            Environment environment = environmentPreparedEvent.getEnvironment();
            System.out.println("environment.getProperty(\"name\"): " + environment.getProperty("name"));
        }
        if (event instanceof ApplicationPreparedEvent) {

        }
    }

    @Override
    public int getOrder() {
        //比 ConfigFileApplicationListener 优先级高
        return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
    }
}

Create Spring Application Context(ConfigurableApplicationContext)

根据前面提到的Prepared 阶段推断出的Web 应用类型对应的ConfigurableApplicationContext实例:

  • Web Reactive: AnnotationConfigReactiveWebServerApplicationContext
  • Web Servlet: AnnotationConfigServletWebServerApplicationContext
  • 非Web: AnnotationConfigApplicationContext
代码语言:javascript
复制
/**
     * Strategy method used to create the {@link ApplicationContext}. By default this
     * method will respect any explicitly set application context or application context
     * class before falling back to a suitable default.
     * @return the application context (not yet refreshed)
     * @see #setApplicationContextClass(Class)
     */
    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, "
                                + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

Create Environment

根据Prepead 阶段推断的Web应用类型创建对应的 ConfigurableEnvironment

  • Web Servlet: StandardServletEnvironment
  • Web Reactive: StandardEnvironment
  • 非Web: StandardEnvironment
代码语言:javascript
复制
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        if (this.webApplicationType == WebApplicationType.SERVLET) {
            return new StandardServletEnvironment();
        }
        return new StandardEnvironment();
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-03-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringApplication Explain
    • How TO Use SpringApplication
      • Customize SpringApplication
        • UseSpringApplicationAPI To Change
        • UseSpringApplicationBuilder API To Change
      • SpringApplication Preparing Stage
        • Configure Spring Boot Bean's Sources
        • Deduce Web Application Type
        • Deduce Main Class
        • Load ApplicationContextInitializer
        • Load ApplicationListener
      • SpringApplication Running Stage
        • Load SpringApplication Run Listener
        • Running SpringApplication Run Listeners
        • Monitor Spring-Boot Event / Spring Event
        • Create Spring Application Context(ConfigurableApplicationContext)
        • Create Environment
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档