zoukankan      html  css  js  c++  java
  • Spring environment 和 applicationContext

    Spring environment 和 applicationContext

    Environment 表示当前应用程序正在运行的环境,表示整个 spring 应用运行的环境信息,存储各种环境变量,如 JDK 信息、磁盘信息、用户自定义的一些属性值等。

    查看源码可知继承接口 PropertyResolver - 属性解析器,用来解析不同属性源 PropertySource 里的 key-value

    /**
    * Interface representing the environment in which the current application is running.
    * ...
    */
    public interface Environment extends PropertyResolver {
        // ...
    }
    

    PropertyResolver

    查看接口 PropertyResolver 的实现,它的继承为

    PropertyResolver -> ConfigurablePropertyResolver -> AbstractPropertyResolver -> PropertySourcesPropertyResolver

    ConfigurablePropertyResolver

    可配置处理类,在 PropertyResolver 的基础上扩展定义类型转换、属性校验、分隔符等一些列的功能。

    AbstractPropertyResolver

    实现了 ConfigurablePropertyResolver 的接口方法,使用 PropertyPlaceholderHelper 处理占位符。

    PropertySourcesPropertyResolver

    具体的实现以封装在 AbstractPropertyResolver 中,PropertySourcesPropertyResolver作为它的子类它只需要提供数据源 propertySources

    public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
    
        @Nullable
        private final PropertySources propertySources;
    
    
        /**
        * Create a new resolver against the given property sources.
        * @param propertySources the set of {@link PropertySource} objects to use
        */
        public PropertySourcesPropertyResolver(@Nullable PropertySources propertySources) {
            this.propertySources = propertySources;
        }
        
        // ...
    }
    

    Environment

    Environment 的继承实现:

    PropertyResolver -> Environment -> ConfigurableEnvironment -> AbstractEnvironment -> StandardEnvironment/StandardServletEnvironment/...

    Environment

    public interface Environment extends PropertyResolver {
        /**
        * Return the set of profiles explicitly made active for this environment.
        */
        String[] getActiveProfiles();
        
        /**
        * Return the set of profiles to be active by default when no active profiles have
    	* been set explicitly.
        */
        String[] getDefaultProfiles();
        
        @Deprecated
    	boolean acceptsProfiles(String... profiles);
        
        /**
        * 判断传入的 profiles 是否激活
        */
        boolean acceptsProfiles(Profiles profiles);
    }
    

    ConfigurableEnvironment

    扩展出了修改和配置 profiles 的一系列方法,包括用户自定义的和系统相关的属性。

    public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
      void setActiveProfiles(String... profiles);
        
      void addActiveProfile(String profile);
       
      void setDefaultProfiles(String... profiles);
      
      MutablePropertySources getPropertySources();
      
      Map<String, Object> getSystemProperties();
        
      Map<String, Object> getSystemEnvironment();
      
      void merge(ConfigurableEnvironment parent);
    }
    

    AbstractEnvironment

    抽象实现类,完成了对 active、default 等相关方法的复写处理。根据注释可知具体的子类主要区别在于它们默认添加的 PropertySource 属性源,

    子类分别有 StandardEnvironment(非 web 容器运行的环境)、StandardServletEnvironment(web容器)、StandardReactiveWebEnvironmentMockEnvironment

    **
     * Abstract base class for {@link Environment} implementations. Supports the notion of
     * reserved default profile names and enables specifying active and default profiles
     * through the {@link #ACTIVE_PROFILES_PROPERTY_NAME} and
     * {@link #DEFAULT_PROFILES_PROPERTY_NAME} properties.
     *
     * <p>Concrete subclasses differ primarily on which {@link PropertySource} objects they
     * add by default. {@code AbstractEnvironment} adds none. Subclasses should contribute
     * property sources through the protected {@link #customizePropertySources(MutablePropertySources)}
     * hook, while clients should customize using {@link ConfigurableEnvironment#getPropertySources()}
     * and working against the {@link MutablePropertySources} API.
     * See {@link ConfigurableEnvironment} javadoc for usage examples.
     *
     * @author Chris Beams
     * @author Juergen Hoeller
     * @since 3.1
     * @see ConfigurableEnvironment
     * @see StandardEnvironment
     */
    public abstract class AbstractEnvironment implements ConfigurableEnvironment {
      // ...   
    }
    

    PropertySource 配置源

    表示 Spring 各种的配置来源,如:

    • MapPropertySource
      • PropertiesPropertySource
    • CompositePropertySource:组合
    • SystemEnvironmentPropertySource:环境变量

    environment 的关系

    Environment -> ConfigurableEnvironment: 父子层次
    ConfigurableEnvironment -> MutablePropertySources: 获取可变多个配置源
    MutablePropertySources -> List PropertySource : 包含多个 PropertySource
    

    StandardServletEnvironment 中,构造器接受配置源 MutablePropertySources,使用 PropertySourcesPropertyResolver 进行解析,把获取的配置存在 environment

    Java 获取配置文件的方式

    1、使用 JDK property (只能获取 String 类型)

    2、apache 的 commons-configuration (提供大多数常见类型的 Value 转换 )

    3、Spring 的 environment

    应用配置的优先级

    通过文档可知不同位置的配置的加载优先级

    Spring Boot 外部化配置官方文档

    优先级的保证:

    public class MutablePropertySources implements PropertySources {
        // 使用 List 存储配置,保证有序性
        private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
        // ...   
    }
    
    public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
        // ...
        @Nullable
        protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
    	if (this.propertySources != null) {
    	    for (PropertySource<?> propertySource : this.propertySources) {
    		if (logger.isTraceEnabled()) {
    		    logger.trace("Searching for key '" + key + "' in PropertySource '" +
    			    propertySource.getName() + "'");
    		}
    		Object value = propertySource.getProperty(key);
    		if (value != null) {
    		    if (resolveNestedPlaceholders && value instanceof String) {
    			value = resolveNestedPlaceholders((String) value);
    		    }
    		    logKeyFound(key, propertySource, value);
                        // 顺序遍历,读取到的时候返回,优先级越高的配置越前
    		    return convertValueIfNecessary(value, targetValueType);
    	        }
    	    }
             }
            if (logger.isTraceEnabled()) {
    	    logger.trace("Could not find key '" + key + "' in any property source");
                
            }
            return null;
        }
    }
    

    Spring 应用上下文 - ApplicationContext

    ApplicationContext 本质是一个维护 Bean 定义以及对象之间协作关系的接口,或者说为应用 application 提供配置的核心接口。

    /**
     * Central interface to provide configuration for an application.
     * This is read-only while the application is running, but may be
     * reloaded if the implementation supports this.
     */
    public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
    		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
                
    }
    

    ApplicationContext 继承 ListableBeanFactoryHierarchicalBeanFactory ,实现了 Bean 的生命周期管理(BeanFactoy)、有序性(ListableBeanFactory)和层次性(HierarchicalBeanFactory),并进行扩展。

    Spring也为我们提供了 ApplicationContext 的多种类型的容器实现,供我们在不同的应用场景选择,例如:

    • AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载上下文定义,适用于 Java 注解的方式

    • AnnotationConfigWebApplicationContext:专门为 web 应用准备的,适用于注解方式

    在 Spring Boot 的启动方法 run() 我们可以看到 Spring Boot 根据当前应用环境 webApplicationType 决定创建相应的 ConfigurableApplicationContext 对象

    run() 内的 prepareEnvironment 监听 ApplicationEnvironmentPreparedEvent 事件,由 listeners 处理,然后 createApplicationContext() 创建上下文

    public class SpringApplicationBuilder {
        public ConfigurableApplicationContext run(String... args) {
    	// ...
    	if (this.running.compareAndSet(false, true)) {
    		synchronized (this.running) {
    			// 创建 应用上下文
    			this.context = build().run(args);
    		}
    	}
    	return this.context;
      }
    }
    
    public class SpringApplication {
        
        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    	// ...
    	this.webApplicationType = WebApplicationType.deduceFromClasspath();
    	// ...
        }
        
       public ConfigurableApplicationContext run(String... args) {
            // ...
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            context = createApplicationContext();
            // ...
        }
        
        protected ConfigurableApplicationContext createApplicationContext() {
    	Class<?> contextClass = this.applicationContextClass;
    	if (contextClass == null) {
    		try {
    			switch (this.webApplicationType) {
    			  case SERVLET:
    				contextClass = Class.forName(DEFAULT_SERVLET_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);
      }
    }
    
  • 相关阅读:
    Vuejs模板绑定
    Vuejs基本使用
    Vuejs简介
    echarts 使用配置模式(含事件)
    JS 对象(Object)和字符串(String)互转
    HTML Meta中添加X-UA-Compatible和IE=Edge,chrome=1有什么作用
    highcharts点击事件系列
    servlet填充Response时,数据转换之content-type
    leetcode-70. Climbing Stairs
    deep copy and shallow copy
  • 原文地址:https://www.cnblogs.com/linyuhong/p/14789274.html
Copyright © 2011-2022 走看看