Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下相关的知识,希望对你有一定的参考价值。

Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下


书接上文:

Spring读源码系列番外篇—02—PropertyResolver的结构体系剖析—上


Environment接口


和Environment相关的接口可以有那么多:

See Also:
PropertyResolver, 
EnvironmentCapable, 
ConfigurableEnvironment, 
AbstractEnvironment, 
StandardEnvironment, 
org.springframework.context.EnvironmentAware, 
org.springframework.context.ConfigurableApplicationContext.getEnvironment, 
org.springframework.context.ConfigurableApplicationContext.setEnvironment, 
org.springframework.context.support.AbstractApplicationContext.createEnvironment

可以看出该接口的发展潜力之大


个人认为这里英文注释有些讲的更加详细,所以我就不翻译了,不然翻译了反而读不懂了

public interface Environment extends PropertyResolver 

	/**
	   获取当前激活的环境
	 */
	String[] getActiveProfiles();

	/**
	 * Return the set of profiles to be active by default when no active profiles have
	 * been set explicitly.
	 */
	String[] getDefaultProfiles();

	/**
Return whether one or more of the given profiles is active or, in the case of no explicit active profiles, 
whether one or more of the given profiles is included in the set of default profiles. If a profile begins with 
'!' the logic is inverted, i.e. the method will return true if the given profile is not active. 
For example, 
env.acceptsProfiles("p1", "!p2") will return true if profile 'p1' is active or 'p2' is not active.
	 */
	@Deprecated
	boolean acceptsProfiles(String... profiles);

	/**
Return whether the active profiles match the given Profiles predicate.
	 */
	boolean acceptsProfiles(Profiles profiles);


Environment顶层接口,主要暴露出来的接口主要功能是获取当前激活环境和默认环境,以及判断传入的环境是否被激活


ConfigurableEnvironment—可配置环境

public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver 
	void setActiveProfiles(String... profiles);
	void addActiveProfile(String profile);
	void setDefaultProfiles(String... profiles);

	/**
	    MutablePropertySources也是拥有一组属性源的集合
	    mutable是可变的意思,意味我们可以自己对返回的属性源进行CRUD
	 */
	MutablePropertySources getPropertySources();

   //System.getProperty()
	Map<String, Object> getSystemProperties();
   
   //System.getenv()
	Map<String, Object> getSystemEnvironment();

    //合并两个环境
	void merge(ConfigurableEnvironment parent);


可配置意味可以修改—通常里面会暴露出大量set接口


AbstractEnvironment----大部分接口的实现,少部分留给子类实现

public abstract class AbstractEnvironment implements ConfigurableEnvironment 

	public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
	public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
	public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
	protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";


	protected final Log logger = LogFactory.getLog(getClass());

	private final Set<String> activeProfiles = new LinkedHashSet<>();

	private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
    
    //可变的属性源集合
	private final MutablePropertySources propertySources;
     //可配置的属性解析器
	private final ConfigurablePropertyResolver propertyResolver;

	public AbstractEnvironment() 
	//如果构造函数没有传入一个属性源集合,那么默认创建一个空的可变的属性源集合
		this(new MutablePropertySources());
	


	protected AbstractEnvironment(MutablePropertySources propertySources) 
		this.propertySources = propertySources;
		//返回的是PropertySourcesPropertyResolver
		this.propertyResolver = createPropertyResolver(propertySources);
		//从名字看是自定义属性源---->说明我们可以尝试去自定义集合中的属性源
		customizePropertySources(propertySources);
	


	protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) 
	//PropertySourcesPropertyResolver讲解过了----PropertyResolver下面的一个具体实现子类
	//它负责从这些属性源中寻找key--->value
		return new PropertySourcesPropertyResolver(propertySources);
	

	protected final ConfigurablePropertyResolver getPropertyResolver() 
		return this.propertyResolver;
	

	//子类通过重新该方法完成对属性源的自定义修改操作---可以进行CRUD  
	protected void customizePropertySources(MutablePropertySources propertySources) 
	
	
	protected Set<String> getReservedDefaultProfiles() 
		return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
	


	//---------------------------------------------------------------------
	// Implementation of ConfigurableEnvironment interface
	//---------------------------------------------------------------------

	@Override
	public String[] getActiveProfiles() 
		return StringUtils.toStringArray(doGetActiveProfiles());
	

//获取激活的
	protected Set<String> doGetActiveProfiles() 
		synchronized (this.activeProfiles) 
		//activeProfiles集合不为空,就直接返回该集合即可
			if (this.activeProfiles.isEmpty()) 
			//否则调用doGetActiveProfilesProperty获取激活的环境
				String profiles = doGetActiveProfilesProperty();
				if (StringUtils.hasText(profiles)) 
				//缓存获取到的激活环境
					setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				
			
			return this.activeProfiles;
		
	

	/**
	 * Return the property value for the active profiles.
	 * @since 5.3.4
	 * @see #ACTIVE_PROFILES_PROPERTY_NAME
	 */
	@Nullable
	protected String doGetActiveProfilesProperty() 
	//尝试从属性源中获取激活的环境
		return getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
	

	@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) 
		//清除之前保留的激活环境集合
			this.activeProfiles.clear();
			//缓存找到的激活环境
			for (String profile : profiles) 
				validateProfile(profile);
				this.activeProfiles.add(profile);
			
		
	

	@Override
	public void addActiveProfile(String profile) 
		if (logger.isDebugEnabled()) 
			logger.debug("Activating profile '" + profile + "'");
		
		validateProfile(profile);
		//每次添加新的激活环境前,会调用doGetActiveProfiles方法
		//这里是顺便将属性源中规定的激活环境也添加进来,顺便清除之前的缓存
		doGetActiveProfiles();
		synchronized (this.activeProfiles) 
			this.activeProfiles.add(profile);
		
	


//和上面获取激活环境套路类似
	@Override
	public String[] getDefaultProfiles() 
		return StringUtils.toStringArray(doGetDefaultProfiles());
	

	protected Set<String> doGetDefaultProfiles() 
		synchronized (this.defaultProfiles) 
			if (this.defaultProfiles.equals(getReservedDefaultProfiles())) 
				String profiles = doGetDefaultProfilesProperty();
				if (StringUtils.hasText(profiles)) 
					setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				
			
			return this.defaultProfiles;
		
	


	@Nullable
	protected String doGetDefaultProfilesProperty() 
		return getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
	


	@Override
	public void setDefaultProfiles(String... profiles) 
		Assert.notNull(profiles, "Profile array must not be null");
		synchronized (this.defaultProfiles) 
			this.defaultProfiles.clear();
			for (String profile : profiles) 
				validateProfile(profile);
				this.defaultProfiles.add(profile);
			
		
	

//!profile表示当前环境没被激活才算有效
	@Override
	@Deprecated
	public boolean acceptsProfiles(String... profiles) 
		Assert.notEmpty(profiles, "Must specify at least one profile");
		for (String profile : profiles) 
			if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') 
				if (!isProfileActive(profile.substring(1))) 
					return true;
				
			
			else if (isProfileActive(profile)) 
				return true;
			
		
		return false;
	

	@Override
	public boolean acceptsProfiles(Profiles profiles) 
		Assert.notNull(profiles, "Profiles must not be null");
		return profiles.matches(this::isProfileActive);
	

	protected boolean isProfileActive(String profile) 
		validateProfile(profile);
		Set<String> currentActiveProfiles = doGetActiveProfiles();
		return (currentActiveProfiles.contains(profile) ||
				(currentActiveProfiles.isEmpty() && doGetDefaultProfiles().contains(profile)));
	


	protected void validateProfile(String profile) 
		if (!StringUtils.hasText(profile)) 
			throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text");
		
		if (profile.charAt(0) == '!') 
			throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator");
		
	

	@Override
	public MutablePropertySources getPropertySources() 
		return this.propertySources;
	

	@Override
	@SuppressWarnings("rawtypes", "unchecked")
	public Map<String, Object> getSystemProperties() 
		try 
			return (Map) System.getProperties();
		
		catch (AccessControlException ex) 
			return (Map) new ReadOnlySystemAttributesMap() 
				@Override
				@Nullable
				protected String getSystemAttribute(String attributeName) 
					try 
						return System.getProperty(attributeName);
					
					catch (AccessControlException ex) 
						if (logger.isInfoEnabled()) 
							logger.info("Caught AccessControlException when accessing system property '" +
									attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
						
						return null;
					
				
			;
		
	

	@Override
	@SuppressWarnings("rawtypes", "unchecked")
	public Map<String, Object> getSystemEnvironment() 
		if (suppressGetenvAccess()) 
			return Collections.emptyMap();
		
		try 
			return (Map) System.getenv();
		
		catch (AccessControlException ex) 
			return (Map) new ReadOnlySystemAttributesMap() 
				@Override
				@Nullable
				protected String getSystemAttribute(String attributeName) 
					try 
						return System.getenv(attributeName);
					
					catch (AccessControlException ex) 
						if (logger.isInfoEnabled()) 
							logger.info("Caught AccessControlException when accessing system environment variable '" +
									attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
						
						return null;
					
				
			;
		
	
	
	protected boolean suppressGetenvAccess() 
		return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME);
	

	@Override
	public void merge(ConfigurableEnvironment parent) 
		for (PropertySource<?> ps : parent.getPropertySources()) 
			if (!this.propertySources.contains(ps.getName())) 
				this.propertySources.addLast(ps);
			
		
		String[] parentActiveProfiles = parent.getActiveProfiles();
		if (!ObjectUtils.isEmpty(parentActiveProfiles)) 
			synchronized (this.activeProfiles) 
				Collections.addAll(this.activeProfiles, parentActiveProfiles);
			
		
		String[] parentDefaultProfiles = parent.getDefaultProfiles();
		if (!ObjectUtils.isEmpty(parentDefaultProfiles)) 
			synchronized (this.defaultProfiles) 
				this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME);
				Collections.addAll(this.defaultProfiles, parentDefaultProfiles);
			
		
	


	//---------------------------------------------------------------------
	// Implementation of ConfigurablePropertyResolver interface
	//---------------------------------------------------------------------

	@Override
	public ConfigurableConversionService getConversionService() 
		return this.propertyResolver.getConversionService();
	

	@Override
	public void setConversionService(ConfigurableConversionService conversionService) 
		this.propertyResolver.setConversionService(conversionService以上是关于Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下的主要内容,如果未能解决你的问题,请参考以下文章

Spring读源码系列番外篇08---BeanWrapper没有那么简单--中

Spring读源码系列番外篇---06----类型转换---下---ConversionService相关家族

Spring读源码系列番外篇---03---PropertyResolver的结构体系剖析---下

Spring读源码系列番外篇---02---PropertyResolver的结构体系剖析---上

Spring读源码系列番外篇---05----类型转换---中---三种全新的类型转换器

重学springboot系列番外篇之RestTemplate