prepareEnvironment

简介: prepareEnvironment

SpringBoot启动流程之(prepareEnvironment)

  • prepareEnvironment流程图:
  • 上一章讲到了,listeners通过帅选,得出了需要执行的listener,并且执行了相关的onApplicationEvent
  • 系统在执行完对应的starting的listeners后,便进行prepareEnvironment,代码如下

 

public ConfigurableApplicationContext run(String...args){
        }
        //记录任务耗时
        StopWatch stopWatch=new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context=null;
        Collection<SpringBootExceptionReporter> exceptionReporters=new ArrayList<>();
        configureHeadlessProperty();
        //加载并实例化META-INF/spring.factories下面的SpringApplicationRunListener所对应的class集合
        SpringApplicationRunListenerslisteners=getRunListeners(args);
        //根据参数决定加载某些listener,并且start
        listeners.starting();
        //SpringApplication的参数封装
        ApplicationArguments applicationArguments=new DefaultApplicationArguments(args);
        //这里便是重点
        ConfigurableEnvironment environment=prepareEnvironment(listeners,applicationArguments);
//下面还有,这里不讲......

prepareEnvironment()方法体

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments){
        // 获取或者根据一定条件创建Environment对象,这里返回的是StandardServletEnvironment()
        ConfigurableEnvironment environment=getOrCreateEnvironment();
        //为Environment设置了系统参数以及一些相关的PropertySource 
        configureEnvironment(environment,applicationArguments.getSourceArgs());
        //对PropertySource转化为ConfigurationPropertySourcesPropertySource
        ConfigurationPropertySources.attach(environment);
        //事件发布(具体逻辑在listeners.start里面讲过了)
        listeners.environmentPrepared(environment);
        //为environment与Binder建立联系(至于为什么,我也不知道,留个????)
        bindToSpringApplication(environment);
        //是否为自定义的环境
        if(!this.isCustomEnvironment){
        //如果不是自定义环境,则会对environment进行格式转换
        environment=new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
        deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
        }

getOrCreateEnvironment()解释:创建了当前应用适配的Environment

private ConfigurableEnvironment getOrCreateEnvironment(){
        //是否存在环境
        if(this.environment!=null){
        return this.environment;
        }
        //根据当前应用类型,加载不同的Environment对象
        //至于怎么获取当前应用类型,在构造SpringApplication时讲了
        switch(this.webApplicationType){
        //servlet环境
        case SERVLET:
        return new StandardServletEnvironment();
        //响应式环境
        case REACTIVE:
        return new StandardReactiveWebEnvironment();
//非web环境
default:
        return new StandardEnvironment();
        }
        }
• StandardServletEnvironment#customizePropertySources(),为Environment配置几个键值对象
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
  @Override
  protected void customizePropertySources(MutablePropertySources propertySources) {
    //往MutablePropertySources添加了名为servletContextInitParams,
    // servletConfigInitParams的StubPropertySource对象
    propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
    propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
    if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
      propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
    }
    //通过父类添加了名为systemEnvironment的PropertiesPropertySource对象
    //通过父类添加了名为systemProperties的SystemEnvironmentPropertySource对象
    super.customizePropertySources(propertySources);
  }
  • 这里主要是获得了四个不同的键值对象,其中最后两个键值对象;systemEnvironment、systemProperties包含了主机的所有信息
  • 主要信息如下

configureEnvironment(environment, applicationArguments.getSourceArgs()):模板方法,将实现委托给了configurePropertySources,configureProfiles    

protectedvoidconfigureEnvironment(ConfigurableEnvironment environment,String[]args){
        //ConversionService:懒汉式线程安全单例模式,管理了一系列bean的转化
        if(this.addConversionService){
        ConversionService conversionService=ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService)conversionService);
        }
        //对 PropertySource进行管理(主要是系统属性的配置),后面会讲
        configurePropertySources(environment,args);
        //这里主要对系统环境的配置,决定激活什么配置文件
        configureProfiles(environment,args);
        }
  • SpringApplication#configurePropertySources(对PropertySources进行优先级管理,或者添加删除一些默认配置)

 

protected void configurePropertySources(ConfigurableEnvironment environment,String[]args){
        //获取当前系统environment的PropertySources
        MutablePropertySources sources=environment.getPropertySources();
        //检测是否存在默认配置,如果有则添加到PropertySources中(低优先级)
        if(this.defaultProperties!=null&&!this.defaultProperties.isEmpty()){
        sources.addLast(new MapPropertySource("",this.defdefaultPropertiesaultProperties));
        }
        //从命令行参数读取参数,并且加入到PropertySources中
        if(this.addCommandLineProperties&&args.length>0){
        String name=CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        //如果原先的PropertySources存在此命令行key
        if(sources.contains(name)){
        PropertySource<?> source=sources.get(name);
        //则新建一个CompositePropertySource对象
        CompositePropertySource composite=new CompositePropertySource(name);
        //并且添加到PropertySources
        composite.addPropertySource(
        new SimpleCommandLinePropertySource("springApplicationCommandLineArgs",args));
        composite.addPropertySource(source);
        //然后替换掉原来的用新的对象替换掉原来的key
        sources.replace(name,composite);
        }
        else{
        //否则直接在最前面添加命令行参数(高优先级) 如:java-jar --server.port......等参数
        sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
        }
        }
  • SpringApplication()#configureProfiles():确定激活什么样的配置文件

 

protected void configureProfiles(ConfigurableEnvironment environment,String[]args){
        Set<String> profiles=new LinkedHashSet<>(this.additionalProfiles);
        profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
        //往下看
        environment.setActiveProfiles(StringUtils.toStringArray(profiles));
        }
  • AbstractEnvironment#setActiveProfiles
public void setActiveProfiles(String...profiles){
        Assert.notNull(profiles,"Profile array must not be null");
        if(logger.isDebugEnabled()){
        logger.debug("Activating profiles "+Arrays.asList(profiles));
        }
synchronized (this.activeProfiles){
        //清除自身的被激活的环境
        this.activeProfiles.clear();
        for(String profile:profiles){
        //验证环境
        validateProfile(profile);
        //确认需要激活的环境
        this.activeProfiles.add(profile);
        }
        }
        }
  • ConfigurationPropertySources.attach(environment):将PropertySources转化为更适配的ConfigurationPropertySourcesPropertySource

public static void attach(Environment environment){
        Assert.isInstanceOf(ConfigurableEnvironment.class,environment);
        //获取当前environment的PropertySources
        MutablePropertySources sources=((ConfigurableEnvironment)environment).getPropertySources();
        PropertySource<?> attached=sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
        if(attached!=null&&attached.getSource()!=sources){
        sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
        attached=null;
        }
        if(attached==null){
        //PropertySources转化为ConfigurationPropertySources,为后续Binder.get(this.environment)打下基础
        sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
        new SpringConfigurationPropertySources(sources)));
        }
        }

listeners.environmentPrepared(environment):事件的发布,分派给具体的listener执行

  • 调用链路:SpringApplication->SpringApplicationRunListeners#environmentPrepared()-> EventPublishingRunListener#environmentPrepared()->SimpleApplicationEventMulticaster#multicastEvent()-> ApplicationListener#onApplicationEvent()
  • 这是在执行listeners.environmentPrepared()的event类型
  • 这是过滤后的listeners,也是onApplicationEvent()的具体分派类型
  • 没有执行listeners.environmentPrepared():
  • 执行listeners之后的:
  • 可以看出在这里发布listeners之后,主要添加了两个对象,一个是random对象,一个则是配置文件application.properties的信息 (PS:这里没讲怎么读取的,因为坑太大,如果有可能,新开一坑,来写listener发布之后以及加载配置信息的流程)

bindToSpringApplication(environment);

  • Binder:包含一个或者多个ConfigurationPropertySources对象的容器(这也是为什么前面需要将PropertySources转换为ConfigurationPropertySources的原因)
protected void bindToSpringApplication(ConfigurableEnvironment environment){
        try{
        //先为environment建立Binder对象,为SpringApplictaion设置key
        Binder.get(environment).bind("spring.main",Bindable.ofInstance(this));
        }
        catch(Exception ex){
        throw new IllegalStateException("Cannot bind to SpringApplication",ex);
        }
        }
目录
相关文章
|
网络协议 MySQL 关系型数据库
|
4月前
|
分布式计算 安全 Java
Spark 编译出现 InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
Spark 编译出现 InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
103 0
|
12月前
|
JavaScript 数据安全/隐私保护
去哪儿pre参数分析
去哪儿pre参数分析
121 0
|
SQL Java 关系型数据库
|
SQL Java 关系型数据库
PreparedStatement 的用法 | 学习笔记
快速学习 PreparedStatement 的用法。
259 1
|
SQL 数据库
PreparedStatement对象
PreparedStatement对象
PAT有几个pat
字符串APPAPT中包含了两个单词“PAT”,其中第一个PAT是第2位§,第4位(A),第6位(T);第二个PAT是第3位§,第4位(A),第6位(T)。 现给定字符串,问一共可以形成多少个PAT?
110 0
浅析 PreparedStatement 和 Statement
PreparedStatement 和 Statement的创建方法、执行方法、返回结果和关闭连接
浅析 PreparedStatement 和 Statement
|
SQL Java 数据库
PreparedStatement 模糊匹配 结果却:Parameter index out of range (1 > number of parameters, which is 0)
PreparedStatement 模糊匹配 结果却:Parameter index out of range (1 > number of parameters, which is 0)
438 0
|
SQL 关系型数据库 Java
JDBC(五)PreparedStatement 详解
PreparedStatement 是一个特殊的Statement对象,如果我们只是来查询或者更新数据的话,最好用PreparedStatement代替Statement,因为它有以下有点: 简化Statement中的操作 提高执行语句的性能 可读性和可维护性更好 安全性更好。
1740 0