spring boot环境初始化过程

先看一下最简单的spring boot中环境中有些什么东西,首先spring boot的版本是1.5.9

@RequestMapping(value = "/hello")
@RestController
public class HelloWorld {

    @Autowired
    private AbstractEnvironment environment;

    @RequestMapping(value = "/world", method = RequestMethod.GET)
    public String world() {

        System.out.println(environment);

        System.out.println(environment.getSystemEnvironment());

        System.out.println(environment.getSystemProperties());

        for (String s : environment.getActiveProfiles()){
            System.out.println(s);
        }

        System.out.println("qwe");

        for (String s : environment.getDefaultProfiles()){
            System.out.println(s);
        }

        return "qwe";

    }
    
}

测试代码

StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='server.ports'}, StubPropertySource {name='servletConfigInitParams'}, ServletContextPropertySource {name='servletContextInitParams'}, MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, PropertiesPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}


这是环境里面所有的变量,接下来就看看这些环境变量是从哪里生成的。首先可以从run的方法中进入,可以看到prepareEnvironment方法用来生成环境。

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        if (!this.webEnvironment) {
            environment = (new EnvironmentConverter(this.getClassLoader())).convertToStandardEnvironmentIfNecessary((ConfigurableEnvironment)environment);
        }

        return (ConfigurableEnvironment)environment;
    }

只需要看3个方法就可以getOrCreateEnvironment,configureEnvironment,environmentPrepared,先来看看getOrCreateEnvironment

    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        } else {
            return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());
        }
    }

这里只做了一步,new StandardServletEnvironment()。接下来看看会初始化一些什么东西

StandardServletEnvironment->StandardEnvironment->AbstractEnvironment。这是一个继承关系,先去初始化AbstractEnvironment中的构造函数

   public AbstractEnvironment() {
        this.propertySources = new MutablePropertySources(this.logger);
        this.propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
        this.customizePropertySources(this.propertySources);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Initialized " + this.getClass().getSimpleName() + " with PropertySources " + this.propertySources);
        }

    }

customizePropertySources方法进行初始化,接下来在StandardServletEnvironment找到了方法

    protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
        propertySources.addLast(new StubPropertySource("servletContextInitParams"));
        if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource("jndiProperties"));
        }

        super.customizePropertySources(propertySources);
    }

这里初始化了servlet的一些参数。这里还调用了父类的方法,接下来看看父类中的方法

  protected void customizePropertySources(MutablePropertySources propertySources) {
        propertySources.addLast(new MapPropertySource("systemProperties", this.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
    }

   发现这里初始化了系统环境变量。

至此大部分的初始化已经完成。

接下来看看configureEnvironment

   protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        this.configurePropertySources(environment, args);
        this.configureProfiles(environment, args);
    }

进入第一个方法

    protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
        MutablePropertySources sources = environment.getPropertySources();
        if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
            sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
        }

        if (this.addCommandLineProperties && args.length > 0) {
            String name = "commandLineArgs";
            if (sources.contains(name)) {
                PropertySource source = sources.get(name);
                CompositePropertySource composite = new CompositePropertySource(name);
                composite.addPropertySource(new SimpleCommandLinePropertySource(name + "-" + args.hashCode(), args));
                composite.addPropertySource(source);
                sources.replace(name, composite);
            } else {
                sources.addFirst(new SimpleCommandLinePropertySource(args));
            }
        }

    }

这里是进行命令行参数的初始化

最后看一下environmentPrepared,本质是ConfigFileApplicationListener类

当广播来的时候,会调用onApplicationEnvironmentPreparedEvent

   private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        List postProcessors = this.loadPostProcessors();
        postProcessors.add(this);
        AnnotationAwareOrderComparator.sort(postProcessors);
        Iterator var3 = postProcessors.iterator();

        while(var3.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
            postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
        }

    }

进入postProcessEnvironment方法

   public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        this.addPropertySources(environment, application.getResourceLoader());
        this.configureIgnoreBeanInfo(environment);
        this.bindToSpringApplication(environment, application);
    }

进入addPropertySources方法

    protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        RandomValuePropertySource.addToEnvironment(environment);
        (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
    }

在这里RandomValuePropertySource添加了环境变量

接下来就差最后一个.yml和.properties文件的加载了。

进入load()方法

       public void load() {
            this.propertiesLoader = new PropertySourcesLoader();
            this.activatedProfiles = false;
            this.profiles = Collections.asLifoQueue(new LinkedList());
            this.processedProfiles = new LinkedList();
            Set initialActiveProfiles = this.initializeActiveProfiles();
            this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
            if (this.profiles.isEmpty()) {
                String[] var2 = this.environment.getDefaultProfiles();
                int var3 = var2.length;

                for(int var4 = 0; var4 < var3; ++var4) {
                    String defaultProfileName = var2[var4];
                    ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
                    if (!this.profiles.contains(defaultProfile)) {
                        this.profiles.add(defaultProfile);
                    }
                }
            }

            this.profiles.add((Object)null);

            ConfigFileApplicationListener.Profile profile;
            label41:
            for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
                profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
                Iterator var8 = this.getSearchLocations().iterator();

                while(true) {
                    while(true) {
                        if (!var8.hasNext()) {
                            continue label41;
                        }

                        String location = (String)var8.next();
                        if (!location.endsWith("/")) {
                            this.load(location, (String)null, profile);
                        } else {
                            Iterator var10 = this.getSearchNames().iterator();

                            while(var10.hasNext()) {
                                String name = (String)var10.next();
                                this.load(location, name, profile);
                            }
                        }
                    }
                }
            }

            this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
        }

先看最下面的循环其中location是需要文件的位置,根据顺序排下来是这样的。file:./config/ 、 file:./ 、 classpath:/config/  、classpath:/ 。name是application,profile可能是"default",这两个分别对应着application-default.yml。

再看看内部的load方法

    private void load(String location, String name, ConfigFileApplicationListener.Profile profile) {
            String group = "profile=" + (profile == null ? "" : profile);
            String ext;
            if (!StringUtils.hasText(name)) {
                this.loadIntoGroup(group, location, profile);
            } else {
                for(Iterator var5 = this.propertiesLoader.getAllFileExtensions().iterator(); var5.hasNext(); this.loadIntoGroup(group, location + name + "." + ext, profile)) {
                    ext = (String)var5.next();
                    if (profile != null) {
                        this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, (ConfigFileApplicationListener.Profile)null);
                        Iterator var7 = this.processedProfiles.iterator();

                        while(var7.hasNext()) {
                            ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var7.next();
                            if (processedProfile != null) {
                                this.loadIntoGroup(group, location + name + "-" + processedProfile + "." + ext, profile);
                            }
                        }

                        this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, profile);
                    }
                }
            }

        }

可以看到在for循环的内部有一个this.loadIntoGroup(group, location + name + "." + ext, profile)

application.properties就是在这里进行初始化

 

你可能感兴趣的:(spring,boot)