美文网首页源码解读
Spring源码4:prepareEnvironment()准备

Spring源码4:prepareEnvironment()准备

作者: ygxing | 来源:发表于2019-07-01 21:15 被阅读0次

    上篇回顾

    上一篇封装命令行参数DefaultApplicationArguments主要作用是处理启动类main函数的参数, 将其封装为一个DefaultApplicationArguments对象, 为prepareEnvironment提供参数


    目录

    1. prepareEnvironment()准备环境
    2. 获取或者创建环境getOrCreateEnvironment()
        2.1 AbstractEnvironment
        2.2 StandardEnvironment
        2.3 StandardServletEnvironment
    3. 配置环境configureEnvironment()
         3.1 配置属性configurePropertySources
         3.2 配置profile
    4. 发布ApplicationEnvironmentPreparedEvent事件
         4.1 ConfigFileApplicationListener
         4.2 AnsiOutputApplicationListener
         4.3 LoggingApplicationListener
         4.4 ClasspathLoggingApplicationListener
         4.5 BackgroundPreinitializer
         4.6 DelegatingApplicationListener
         4.7 FileEncodingApplicationListener
    5. bindToSpringApplication绑定环境
    6. 环境转换EnvironmentConverter
    7. ConfigurationPropertySources.attach(environment)
    8. 总结

    1. prepareEnvironment()准备环境

    这一步的主要作用按顺序加载命令行参数, 系统参数和外部配置文件, 创建并配置Web环境, 获取profiles.active属性, 并发布ApplicationEnvironmentPreparedEvent事件, 之后获取属性时, 按顺序获取, 获取到就立即返回, 实现了属性之间的合理加载与替换

    public class SpringApplication {
      
        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();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                        args);
                //本文重点
                //准备环境变量
                ConfigurableEnvironment environment = prepareEnvironment(listeners,
                        applicationArguments);
        }
    
        //准备环境方法
        private ConfigurableEnvironment prepareEnvironment(
                SpringApplicationRunListeners listeners,
                ApplicationArguments applicationArguments) {
            //获取或者创建环境
            ConfigurableEnvironment environment = getOrCreateEnvironment();
            //配置环境
            configureEnvironment(environment, applicationArguments.getSourceArgs());
            //发布环境准备事件
            listeners.environmentPrepared(environment);
            //Application绑定环境
            bindToSpringApplication(environment);
            
            if (!this.isCustomEnvironment) {
                //环境转换
                //如果environment.class和模块使用的EnvironmentClass()不一致
                //那么转换成一样的
                environment = new EnvironmentConverter(getClassLoader())
                        .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
            }
            //将环境依附到PropertySources
            ConfigurationPropertySources.attach(environment);
            return environment;
        }
    }
    

    2.获取或者创建环境getOrCreateEnvironment()

    我们的项目的webApplicationType为SERVLET, 所以我们环境是StandardServletEnvironment

    //获取或创建环境
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            //SERVLET环境
            return new StandardServletEnvironment();
        case REACTIVE:
            //REACTIVE环境
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }
    

    StandardServletEnvironment类继承关系如下, 所以我们首先分析抽象父类AbstractEnvironment的代码, 然后分析StandardEnvironment代码, 最后分析StandardServletEnvironment

    2.1 AbstractEnvironment

    定义了子类需要实现的类, 并通过模板方法, 在构造函数中, 调用子类的customizePropertySources()方法, 将环境配置全部放入this.propertySources中, AbstractEnvironment实现了getActiveProfiles和setActiveProfiles方法, 分别用来获取和设备spring.profiles.active属性的配置

    //抽象环境类
    public abstract class AbstractEnvironment implements ConfigurableEnvironment {
        
        //配置是否允许获取SystemEnvironment的配置
        public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
    
        //spring启动profile
        public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
    
        //spring默认profile
        public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
    
        //默认的profile名称
        protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
        
        //用来维护属性列表
        private final MutablePropertySources propertySources = new MutablePropertySources();
     
        //构造函数
        //调用了customizePropertySources方法
        //customizePropertySources方法由子类实现
        public AbstractEnvironment() {
            customizePropertySources(this.propertySources);
        }
        
        //空方法
        //鼓励子类继承实现
        protected void customizePropertySources(MutablePropertySources propertySources) {}
        
        //获取系统属性
       public Map<String, Object> getSystemEnvironment() {
            if (suppressGetenvAccess()) {
                //如果spring.getenv.ignore配置为true,
                //那么返回空map
                return Collections.emptyMap();
            }
            try {
                //返回系统属性
                return (Map) System.getenv();
            }
            catch (AccessControlException ex) {
                //...
            }
        }
        
        /**
         * 获取activeProfiles
         */
        @Override
        public String[] getActiveProfiles() {
            return StringUtils.toStringArray(doGetActiveProfiles());
        }
    
        /**
         * 获取activeProfiles
         */
        protected Set<String> doGetActiveProfiles() {
            //上锁
            synchronized (this.activeProfiles) {
                if (this.activeProfiles.isEmpty()) {
                    //如果activeProfiles为空
                    //那么从propertySources中获取
                    //并且进行了占位符的处理
                    String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
                    if (StringUtils.hasText(profiles)) {
                        //profile保存到activeProfiles成员变量中
                        setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
                                StringUtils.trimAllWhitespace(profiles)));
                    }
                }
                return this.activeProfiles;
            }
        }
    
        @Override
        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) {
                //清空activeProfiles
                this.activeProfiles.clear();
                for (String profile : profiles) {
                    validateProfile(profile);
                    //重新添加到activeProfiles变量中
                    this.activeProfiles.add(profile);
                }
            }
        }
    }
    
    2.2 StandardEnvironment

    StandardEnvironment继承了AbstractEnvironment, customizePropertySources代码执行步骤有:

    • 先添加数据systemProperties(系统属性)到父类的propertySource末尾
    • 再添加systemEnvironment(系统环境变量)维护到父类的propertySource末尾
    public class StandardEnvironment extends AbstractEnvironment {
        //环境变量
        public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
    
        //系统属性
        public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
    
        //重写父类customizePropertySources方法
        //在实例化对象的过程中调用
        @Override
        protected void customizePropertySources(MutablePropertySources propertySources) {
            //获取systemProperties(系统属性), 添加到propertySources的末尾
            propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
            
            //获取systemEnvironment(系统环境变量), 添加到propertySources的末尾
            propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
        }
    }
    
    2.3 StandardServletEnvironment

    我们获取的环境是一个StandardServletEnvironment实例, 实例化StandardServletEnvironment的步骤有3个步骤

    1. 调用抽象父类AbstractEnvironment的构造函数
    2. 调用当前类的customizePropertySources方法
      • propertySources列表末尾添加一个名称为servletConfigInitParams的空配置
      • propertySources列表末尾再添加一个名称为servletContextInitParams的空配置
      • 如果jndi可用, propertySources列表末尾末尾在添加一个名称为jndiProperties的空配置, 由于我们没有使用jndi, 所以不会添加该配置
    3. 调用父类StandardEnvironment的customizePropertySources方法
      • propertySources末尾添加systemProperties(系统属性)
      • propertySources末尾获取systemEnvironment(系统环境变量)

    所以当前StandardServletEnvironment对象的propertySources, 按顺序排列为servletConfigInitParams, servletContextInitParams, systemProperties, systemEnvironment

    public class StandardServletEnvironment对象的 extends StandardEnvironment implements ConfigurableWebEnvironment {
    
        //servlet容器初始化参数
        public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
    
        //servlet配置初始化参数
        public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
    
        //jndi属性
        public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
    
    
        @Override
        protected void customizePropertySources(MutablePropertySources propertySources) {
            //末尾添加一个名称为servletContextInitParams的空配置
            propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
            //末尾再添加一个名称为servletContextInitParams的空配置
            propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
            if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
                //如果jndi配置可用
                //末尾在添加一个名称为jndiProperties的空配置
                propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
            }
            //调用父类StandardEnvironment的customizePropertySources方法
            super.customizePropertySources(propertySources);
        }
    }
    
    public abstract class PropertySource<T> {
        public static class StubPropertySource extends PropertySource<Object> {
            //source为一个空object
            public StubPropertySource(String name) {
                super(name, new Object());
            }
            @Override
            @Nullable
            public String getProperty(String name) {
                return null;
            }
        }
    
        //私有静态内部类
        //标记类,用于实现排序
        static class ComparisonPropertySource extends StubPropertySource {}
    }
    

    3.配置环境configureEnvironment()

    首先, 为environment配置共享的类型转换服务, 然后将defaultProperties和命令行参数分别添加到environment的propertySources中

    protected void configureEnvironment(ConfigurableEnvironment environment,
                String[] args) {
            if (this.addConversionService) {
                //默认为true
                //environment中配置各个转换类
                ConversionService conversionService = ApplicationConversionService
                        .getSharedInstance();
                environment.setConversionService(
                        (ConfigurableConversionService) conversionService);
            }
            //3.1配置属性
            configurePropertySources(environment, args);
            //3.2配置profile
            configureProfiles(environment, args);
        }
    
    3.1 配置属性configurePropertySources
    • 如果默认属性defaultProperties不为空,那么将会添加到environment的propertySources末尾
    • 如果当前environment的propertySources包含commandLineArgs命令行参数, 那么替换为springApplicationCommandLineArgs
    • 如果当前environment的propertySources不包含commandLineArgs, 那么添加一个commandLineArgs到propertySources的首部, SimpleCommandLinePropertySource的代码解析在封装命令行参数DefaultApplicationArguments已经分析过了
    • 由于我们没有配置defaultProperties和commandLineArgs, 所以我们只添加了一个commandLineArgs到propertySources首部
    • 当前propertySources的顺序为:
      • commandLineArgs, servletConfigInitParams, servletContextInitParams, systemProperties, systemEnvironment
    //传入参数为StandardServletEnvironment和命令行参数
    protected void configurePropertySources(ConfigurableEnvironment environment,
                String[] args) {,
            //调用AbstractEnvironment的getPropertySources()方法
            //获取之前配置的所有属性
            MutablePropertySources sources = environment.getPropertySources();
            if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
                //如果this.defaultProperties不为null
                //那么添加defaultProperties到propertySources的末尾
                sources.addLast(
                        new MapPropertySource("defaultProperties", this.defaultProperties));
            }
            if (this.addCommandLineProperties && args.length > 0) {
                //如果存在命令行参数
                String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
                if (sources.contains(name)) {
                    //如果sources中包含了"commandLineArgs",
                    //那么将其替换为"springApplicationCommandLineArgs"
                    PropertySource<?> source = sources.get(name);
                    //先将"commandLineArgs"修改为null,
                    CompositePropertySource composite = new CompositePropertySource(name);
                    //然后新增一个PropertySource
                    //name为"springApplicationCommandLineArgs",
                    //source不变
                    composite.addPropertySource(new SimpleCommandLinePropertySource(
                            "springApplicationCommandLineArgs", args));
                    composite.addPropertySource(source);
                    //替换
                    sources.replace(name, composite);
                }
                else {
                    //如果propertySources的中不包含"commandLineArgs"
                    //将命令行参数放在propertySources的首位
                    sources.addFirst(new SimpleCommandLinePropertySource(args));
                }
            }
        }
    
    3.2 配置profile

    将this.additionalProfiles和environment.getActiveProfiles()组合到一起, 重新赋值给environment的activeProfiles

    //传入参数为StandardServletEnvironment和命令行参数
    protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
        //调用的是AbstractEnvironment的getActiveProfiles()方法
        environment.getActiveProfiles();
        Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
        //再次获取和配置profile
        profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
        //设置environment的profile
        environment.setActiveProfiles(StringUtils.toStringArray(profiles));
    }
    

    4.发布ApplicationEnvironmentPreparedEvent事件

    1. listeners.environmentPrepared(environment), 代码之前已经分析过了
    2. 对该事件该兴趣的监听器有
      • ConfigFileApplicationListener
      • AnsiOutputApplicationListener
      • LoggingApplicationListener
      • ClasspathLoggingApplicationListener
      • BackgroundPreinitializer
      • DelegatingApplicationListener
      • FileEncodingApplicationListener
    4.1 ConfigFileApplicationListener

    调用SpringFactoriesLoader.loadFactories()方法, 获取EnvironmentPostProcessor的子类列表, 然后将自己加入到子类列表中, 然后按@Order注解排序, 然后调用各个EnvironmentPostProcessor的postProcessEnvironment方法, 获取到的EnvironmentPostProcessor子类有

    1. SystemEnvironmentPropertySourceEnvironmentPostProcessor
    2. SpringApplicationJsonEnvironmentPostProcessor
    3. CloudFoundryVcapEnvironmentPostProcessor
    4. ConfigFileApplicationListener
    public class ConfigFileApplicationListener
            implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {       
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof ApplicationEnvironmentPreparedEvent) {
                //处理environmentPrepared事件
                onApplicationEnvironmentPreparedEvent(
                        (ApplicationEnvironmentPreparedEvent) event);
            }
            if (event instanceof ApplicationPreparedEvent) {
                //之后处理applicationPrepared事件
                onApplicationPreparedEvent(event);
            }
        }
    
        private void onApplicationEnvironmentPreparedEvent(
                ApplicationEnvironmentPreparedEvent event) {
            List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
            //将this添加到postProcessors中
            postProcessors.add(this);
            //通过注解Order排序
            AnnotationAwareOrderComparator.sort(postProcessors);
            for (EnvironmentPostProcessor postProcessor : postProcessors) {
                //执行每个postProcessor的postProcessEnvironment方法
                postProcessor.postProcessEnvironment(event.getEnvironment(),
                        event.getSpringApplication());
            }
        }
    
        List<EnvironmentPostProcessor> loadPostProcessors() {
            //这个方法在初始化SpringApplication实例已经讲过了
            //获取到的EnvironmentPostProcessor列表有
            //SystemEnvironmentPropertySourceEnvironmentPostProcessor
            //SpringApplicationJsonEnvironmentPostProcessor
            //CloudFoundryVcapEnvironmentPostProcessor
            return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,
                    getClass().getClassLoader());
        }
    }
    
    SystemEnvironmentPropertySourceEnvironmentPostProcessor

    获取名称为systemEnvironment的属性, 替换为OriginAwareSystemEnvironmentPropertySource类型的PropertySource

    public class SystemEnvironmentPropertySourceEnvironmentPostProcessor
            implements EnvironmentPostProcessor, Ordered {
            
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                SpringApplication application) {
            //名称为systemEnvironment的属性
            String sourceName = StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
            PropertySource<?> propertySource = environment.getPropertySources()
                    .get(sourceName);
            if (propertySource != null) {
                //替换属性
                replacePropertySource(environment, sourceName, propertySource);
            }
        }
        //替换属性
        private void replacePropertySource(ConfigurableEnvironment environment,
                String sourceName, PropertySource<?> propertySource) {
            Map<String, Object> originalSource = (Map<String, Object>) propertySource
                    .getSource();
            //将systemEnvironment的属性转换为OriginAwareSystemEnvironmentPropertySource类型
            SystemEnvironmentPropertySource source = new OriginAwareSystemEnvironmentPropertySource(
                    sourceName, originalSource);
            //然后替换原有的属性
            environment.getPropertySources().replace(sourceName, source);
        }
    }
    
    SpringApplicationJsonEnvironmentPostProcessor

    获取AbstractEnvironment的成员变量PropertySources中名称为spring.application.json的属性, 将其转换为Map, 添加到jndiProperties或者systemProperties属性之前

    public class SpringApplicationJsonEnvironmentPostProcessor
            implements EnvironmentPostProcessor, Ordered {
            
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                SpringApplication application) {
            MutablePropertySources propertySources = environment.getPropertySources();
            //将环境中spring.application.json配置转化为JsonPropertySource
            //然后添加到属性中
            propertySources.stream().map(JsonPropertyValue::get).filter(Objects::nonNull)
                    .findFirst().ifPresent((v) -> processJson(environment, v));
        }
    
        private void processJson(ConfigurableEnvironment environment,
                JsonPropertyValue propertyValue) {
            //处理json
            JsonParser parser = JsonParserFactory.getJsonParser();
            Map<String, Object> map = parser.parseMap(propertyValue.getJson());
            if (!map.isEmpty()) {
                //默认放到jndiProperties 或者systemProperties之前
                addJsonPropertySource(environment,
                        new JsonPropertySource(propertyValue, flatten(map)));
            }
        }
    }
    
    CloudFoundryVcapEnvironmentPostProcessor

    如果environment激活了 Cloud Founry, 那么在commandLineArgs属性之后, 添加一个vcap属性的配置

    public class CloudFoundryVcapEnvironmentPostProcessor
            implements EnvironmentPostProcessor, Ordered {
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                SpringApplication application) {
            //如果environment激活了 Cloud Founry
            if (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {
                //那么添加对Cloud Founry的支持
                Properties properties = new Properties();
                JsonParser jsonParser = JsonParserFactory.getJsonParser();
                addWithPrefix(properties,
                        getPropertiesFromApplication(environment, jsonParser),
                        "vcap.application.");
                addWithPrefix(properties, getPropertiesFromServices(environment, jsonParser),
                        "vcap.services.");
                //然后在environment添加一个vcap的配置
                MutablePropertySources propertySources = environment.getPropertySources();
                if (propertySources.contains(
                        CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
                    propertySources.addAfter(
                            CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
                            new PropertiesPropertySource("vcap", properties));
                }
                else {
                    propertySources
                            .addFirst(new PropertiesPropertySource("vcap", properties));
                }
            }
        }
    }
    
    ConfigFileApplicationListener

    在systemEnvironment属性之后, 添加random属性

    public class ConfigFileApplicationListener
            implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
        
        //加载配置文件的默认路径   
        private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
    
        
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment environment,
                SpringApplication application) {
            addPropertySources(environment, application.getResourceLoader());
        }
        
        protected void addPropertySources(ConfigurableEnvironment environment,
                ResourceLoader resourceLoader) {
            //在systemEnvironment属性之后,添加random属性
            RandomValuePropertySource.addToEnvironment(environment);
            //读取配置文件
            new Loader(environment, resourceLoader).load();
        }
        
        //内部类, 加载配置文件 
        private class Loader {
    
            Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
                this.environment = environment;
                this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(
                        this.environment);
                //resourceLoader实例化为DefaultResourceLoader
                this.resourceLoader = (resourceLoader != null) ? resourceLoader
                        : new DefaultResourceLoader();
                
                //PropertiesPropertySourceLoader加载properties文件
                //YamlPropertySourceLoader加载yml文件
                this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(
                        PropertySourceLoader.class, getClass().getClassLoader());
            }
    
            public void load() {
                this.profiles = new LinkedList<>();
                this.processedProfiles = new LinkedList<>();
                this.activatedProfiles = false;
                this.loaded = new LinkedHashMap<>();
                //获取profile属性,添加到this.profiles列表中
                initializeProfiles();
                while (!this.profiles.isEmpty()) {
                    Profile profile = this.profiles.poll();
                    if (profile != null && !profile.isDefaultProfile()) {
                        addProfileToEnvironment(profile.getName());
                    }
                    //遍历profile
                    //加载文件
                    load(profile, this::getPositiveProfileFilter,
                            addToLoaded(MutablePropertySources::addLast, false));
                    this.processedProfiles.add(profile);
                }
                //将profile属性加到environment中
                resetEnvironmentProfiles(this.processedProfiles);
                //获取配置, 加入到this.loaded中
                load(null, this::getNegativeProfileFilter,
                        addToLoaded(MutablePropertySources::addFirst, true));
                //将this.loaded按顺序添加到environment的propertySources中
                //如果存在defaultProperties,放在defaultProperties之前
                //如果不存在defaultProperties,直接添加到最后
                addLoadedPropertySources();
            }
        }
                
    }
    
    4.2 AnsiOutputApplicationListener

    字符输出监听器, 用于调整控制台显示的打印字符的各种颜色

    public class AnsiOutputApplicationListener
            implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
    
        @Override
        public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
            ConfigurableEnvironment environment = event.getEnvironment();
            //控制台打印字符显示各种颜色
            //例如:设置spring.output.ansi.enabled=ALWAYS
            Binder.get(environment)
                    .bind("spring.output.ansi.enabled", AnsiOutput.Enabled.class)
                    .ifBound(AnsiOutput::setEnabled);
            AnsiOutput.setConsoleAvailable(environment
                    .getProperty("spring.output.ansi.console-available", Boolean.class));
        }
    }
    
    4.3 LoggingApplicationListener

    日志监听器, 初始化日志配置

    public class LoggingApplicationListener implements GenericApplicationListener {
        //处理EnvironmentPrepared事件
        private void onApplicationEnvironmentPreparedEvent(
                ApplicationEnvironmentPreparedEvent event) {
            if (this.loggingSystem == null) {
                //在Starting事件中,我们已经初始化了loggingSystem
                //我们使用的是LogbackLoggingSystem
                this.loggingSystem = LoggingSystem
                        .get(event.getSpringApplication().getClassLoader());
            }
            initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
        }
        //初始化日志
        protected void initialize(ConfigurableEnvironment environment,
            ClassLoader classLoader) {
            //应用环境属性
            new LoggingSystemProperties(environment).apply();
            LogFile logFile = LogFile.get(environment);
            if (logFile != null) {
                logFile.applyToSystemProperties();
            }
            //应用debug/trace参数
            initializeEarlyLoggingLevel(environment);
            //加载日志配置文件,应用环境属性
            initializeSystem(environment, this.loggingSystem, logFile);
            //根据环境属性设置日志输出级别
            initializeFinalLoggingLevels(environment, this.loggingSystem);
            //注册shutdown处理方式
            registerShutdownHookIfNecessary(environment, this.loggingSystem);
        }
    }
    
    4.4 ClasspathLoggingApplicationListener

    打印debug日志, 记录当前classpath

    public final class ClasspathLoggingApplicationListener
            implements GenericApplicationListener {
    
        private static final int ORDER = LoggingApplicationListener.DEFAULT_ORDER + 1;
    
        private static final Log logger = LogFactory
                .getLog(ClasspathLoggingApplicationListener.class);
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (logger.isDebugEnabled()) {
                if (event instanceof ApplicationEnvironmentPreparedEvent) {
                    //处理EnvironmentPrepared事件
                    //debug记录当前classpath
                    logger.debug("Application started with classpath: " + getClasspath());
                }
                else if (event instanceof ApplicationFailedEvent) {
                    logger.debug(
                            "Application failed to start with classpath: " + getClasspath());
                }
            }
        }
        
        private String getClasspath() {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            if (classLoader instanceof URLClassLoader) {
                //获取classLoader加载类和资源的搜索路径
                return Arrays.toString(((URLClassLoader) classLoader).getURLs());
            }
            return "unknown";
        }
    }
    
    4.5 BackgroundPreinitializer

    扩展点, 目前只关注Starting, Ready和Failed事件, EnvironmentPrepared事件不做处理

    4.6 DelegatingApplicationListener 委托监听器

    扩展点, 将当前的EnvironmentPrepared事件, 广播给其他关注该事件的Environment监听器, 目前没有做任何操作

    public class DelegatingApplicationListener
            implements ApplicationListener<ApplicationEvent>, Ordered {
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
            if (event instanceof ApplicationEnvironmentPreparedEvent) {
                List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
                        ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
                if (delegates.isEmpty()) {
                    //如果delegates为空,则立即返回
                    return;
                }
                this.multicaster = new SimpleApplicationEventMulticaster();
                for (ApplicationListener<ApplicationEvent> listener : delegates) {
                    this.multicaster.addApplicationListener(listener);
                }
            }
            if (this.multicaster != null) {
                this.multicaster.multicastEvent(event);
            }
        }
    }
    
    4.7 FileEncodingApplicationListener

    如果指定了spring.mandatory-file-encoding属性, 如果系统属性file.encoding和spring.mandatory-file-encoding不一致的话, 抛出异常

    public class FileEncodingApplicationListener
            implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
    
        @Override
        public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
            ConfigurableEnvironment environment = event.getEnvironment();
            if (!environment.containsProperty("spring.mandatory-file-encoding")) {
                //如果环境不包含spring.mandatory-file-encoding属性
                //则立即返回
                return;
            }
            //获取系统指定编码
            String encoding = System.getProperty("file.encoding");
            String desired = environment.getProperty("spring.mandatory-file-encoding");
            if (encoding != null && !desired.equalsIgnoreCase(encoding)) {
                //系统编码和指定编码不一致,那么报错
                logger.error("System property 'file.encoding' is currently '" + encoding
                        + "'. It should be '" + desired
                        + "' (as defined in 'spring.mandatoryFileEncoding').");
                logger.error("Environment variable LANG is '" + System.getenv("LANG")
                        + "'. You could use a locale setting that matches encoding='"
                        + desired + "'.");
                logger.error("Environment variable LC_ALL is '" + System.getenv("LC_ALL")
                        + "'. You could use a locale setting that matches encoding='"
                        + desired + "'.");
                throw new IllegalStateException(
                        "The Java Virtual Machine has not been configured to use the "
                                + "desired default character encoding (" + desired + ").");
            }
        }
    }
    

    5. bindToSpringApplication绑定环境

    //如果指定了main函数,那么会将当前环境绑定到指定的SpringApplication中
    Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
    

    6. 环境转换EnvironmentConverter

    如果没有调用了setEnvironment方法设置了环境, 那么将自定义environment转换为StandardEnvironment

    final class EnvironmentConverter {
        //环境转换
        StandardEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment,
                Class<? extends StandardEnvironment> type) {
            if (type.equals(environment.getClass())) {
                return (StandardEnvironment) environment;
            }
            //environment.getClass()不是StandardEnvironment的实例
            return convertEnvironment(environment, type);
        }
        
        //环境转换
        private StandardEnvironment convertEnvironment(ConfigurableEnvironment environment,
                Class<? extends StandardEnvironment> type) {
            //新建一个StandardEnvironment实例
            //然后赋值
            StandardEnvironment result = createEnvironment(type);
            result.setActiveProfiles(environment.getActiveProfiles());
            result.setConversionService(environment.getConversionService());
            copyPropertySources(environment, result);
            return result;
        }
    }
    

    7. ConfigurationPropertySources.attach(environment)

    如果配置了configurationProperties属性, 那么将其放在environment的propertySources的首部

    public final class ConfigurationPropertySources {
    
        //配置属性
        private static final String ATTACHED_PROPERTY_SOURCE_NAME = "configurationProperties";
    
        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转换为SpringConfigurationPropertySources,放在首位
                sources.addFirst(new ConfigurationPropertySourcesPropertySource(
                        ATTACHED_PROPERTY_SOURCE_NAME,
                        new SpringConfigurationPropertySources(sources)));
            }
        }
    }
    

    8.总结

    1. 调用getOrCreateEnvironment()方法
      • 创建了StandardServletEnvironment的实例
      • 在AbstractEnvironment的propertySources中按顺序添加了名称为servletConfigInitParams, servletContextInitParams, jndiProperties, systemProperties, systemEnvironment的属性
    2. 调用configurePropertySources()方法
      • 在AbstractEnvironment的propertySources末尾添加defaultProperties属性配置
      • 添加commandLineArgs,到propertySources首部
      • 获取spring.profiles.active属性
    3. 发布ApplicationEnvironmentPreparedEvent事件, 支持该事件的监听器有
      • ConfigFileApplicationListener获取了四个EnvironmentPostProcessor, 分别执行他们的postProcessEnvironment方法
        • SystemEnvironmentPropertySourceEnvironmentPostProcessor 将systemEnvironment属性的类型替换为SystemEnvironmentPropertySource
        • SpringApplicationJsonEnvironmentPostProcessor, 添加spring.application.json属性到jndiProperties或者systemProperties之前
        • CloudFoundryVcapEnvironmentPostProcessor 添加vcap属性到commandLineArgs之后
        • ConfigFileApplicationListener, 首先添加random属性到systemEnvironment之后, 再读取配置文件, 加载到defaultProperties属性之前
      • AnsiOutputApplicationListener 配置控制台打印字符串的颜色
      • LoggingApplicationListener 初始化日志配置
      • ClasspathLoggingApplicationListener debug打印classpath日志
      • BackgroundPreinitializer 没有做任何操作
      • DelegatingApplicationListener 没有做任何操作
      • FileEncodingApplicationListener 判断file.encoding和spring.mandatory-file-encoding是否一致
    4. 将当前环境绑定到spring.main配置的main函数中
    5. 如果设置好了自定义environment, 那么将其转换为StandardEnvironment
    6. 如果配置了configurationProperties属性, 那么将其放在environment的propertySources的首部
    7. environment的propertySources中属性列表顺序为configurationProperties, commandLineArgs, vcap, servletConfigInitParams, servletContextInitParams, spring.application.json, jndiProperties, systemProperties, systemEnvironment, random, 配置文件, defaultProperties

    下一篇

    我们将会在下一篇printBanner()打印Banner, 研究如何打印Banner

    相关文章

      网友评论

        本文标题:Spring源码4:prepareEnvironment()准备

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