spring-core env包PropertySource接口源码解析

一、接口类继承图

spring-core env包PropertySource接口源码解析_第1张图片

   二、接口类功能概述与实现  

     PropertySource是抽象类,表示一个键值对,注意该类重写了equals()和hashCode()方法,提供了一个named(String name)方法用于构造基于name的PropertySource的空实现,从而便于PropertySource 集合中查找指定属性命的PropertySource。用法如MutablePropertySources中的下列代码:

    @Override
	@Nullable
	public PropertySource get(String name) {
		int index = this.propertySourceList.indexOf(PropertySource.named(name));
		return (index != -1 ? this.propertySourceList.get(index) : null);
	}

      EnumerablePropertySource也是抽象类,继承PropertySource,增加了String[] getPropertyNames()抽象方法。
     CommandLinePropertySource是抽象类,继承自EnumerablePropertySource,增加boolean containsOption(String name),
List getOptionValues(String name),List getNonOptionArgs()三个方法,其中OptionValue指的是命令行中以--开头的参数,NonOptionArgs指的不是以--开头的参数,如--o1=v1 --o2=v2 /path/to/file1 /path/to/file2.
    SimpleCommandLinePropertySource和JOptCommandLinePropertySource都是CommandLinePropertySource的实现类,SimpleCommandLinePropertySource是通过SimpleCommandLineArgsParser类解析命令行参数,JOptCommandLinePropertySource是通过OptionParser类解析,依赖JOptSimple这个命令行解析工具包,参考如下测试用例: 

      @Test
	public void withDefaultNonOptionArgsNameAndNonOptionArgsPresent() {
		OptionParser parser = new OptionParser();
		parser.accepts("o1").withRequiredArg().withValuesSeparatedBy(",");
		parser.accepts("o2");
		OptionSet optionSet = parser.parse("--o1=v1,v2", "noa1", "--o2", "noa2");
		CommandLinePropertySource ps = new JOptCommandLinePropertySource(optionSet);

		assertThat(ps.containsProperty("nonOptionArgs"), is(true));
		assertThat(ps.containsProperty("o1"), is(true));
		assertThat(ps.containsProperty("o2"), is(true));
		assertEquals(Arrays.asList("v1","v2"), ps.getOptionValues("o1"));
		assertThat(ps.getProperty("o1"), equalTo("v1,v2"));

		String nonOptionArgs = (String)ps.getProperty("nonOptionArgs");
		assertThat(nonOptionArgs, equalTo("noa1,noa2"));
	}

   MapPropertySource是EnumerablePropertySource的实现类,Source的类型是Map。PropertiesPropertySource和SystemEnvironmentPropertySource继承自MapPropertySource,PropertiesPropertySource增加了PropertiesPropertySource(String name, Properties source)的构造方法,SystemEnvironmentPropertySource改写了getProperty(String name)方法的实现,从而适配多种环境变量格式,比如获取属性foo.bar的值,会依次尝试获取foo.bar,foo_bar,FOO.BAR,FOO_BAR四个name直到获取值为止。

       PropertySources接口继承自Iterable>,定义了多个PropertySource的迭代接口。只有一个默认的实现类MutablePropertySources,通过CopyOnWriteArrayList保存多个PropertySources对象,并增加了维护PropertySource在列表中的具体位置的接口。

       重点关注Profiles接口及其关联的解析类ProfilesParser。Profiles的定义如下:

@FunctionalInterface
public interface Profiles {

	boolean matches(Predicate activeProfiles);


	static Profiles of(String... profiles) {
		return ProfilesParser.parse(profiles);
	}

}

 ProfilesParser的代码解读如下:

final class ProfilesParser {

	private ProfilesParser() {
	}


	static Profiles parse(String... expressions) {
		Assert.notEmpty(expressions, "Must specify at least one profile");
		Profiles[] parsed = new Profiles[expressions.length];
		for (int i = 0; i < expressions.length; i++) {
			//把每个表达式解析成对应的Profiles
			parsed[i] = parseExpression(expressions[i]);
		}
		//对多个Profiles做整合
		return new ParsedProfiles(expressions, parsed);
	}

	private static Profiles parseExpression(String expression) {
		Assert.hasText(expression, () -> "Invalid profile expression [" + expression + "]: must contain text");
		//()&|!为分隔符,true表示分隔符也会被nextToken()方法返回
		StringTokenizer tokens = new StringTokenizer(expression, "()&|!", true);
		return parseTokens(expression, tokens);
	}

	private static Profiles parseTokens(String expression, StringTokenizer tokens) {
		List elements = new ArrayList<>();
		Operator operator = null;
		while (tokens.hasMoreTokens()) {
			String token = tokens.nextToken().trim();
			if (token.isEmpty()) {
				continue;
			}
			switch (token) {
				case "(":
					//此处是递归调用,注意使用的都是一个StringTokenizer对象
					elements.add(parseTokens(expression, tokens));
					break;
				case "&":
					//限制operator为null或者AND是为了确保表达式是规范的,A&B|C是不规范的,必 
                    须是(A&B)|C,否则抛异常
					assertWellFormed(expression, operator == null || operator == 
                    Operator.AND);
					operator = Operator.AND;
					break;
				case "|":
					assertWellFormed(expression, operator == null || operator == 
                    Operator.OR);
					operator = Operator.OR;
					break;
				case "!":
					//对返回的Profiles执行not操作
					elements.add(not(parseTokens(expression, tokens)));
					break;
				case ")":
					//elements保存从(开始的解析的多个Profiles,遇到)则将多个Profiles做合并操 
                      作,同时清空
					//elements,将合并后的对象放入进去
					Profiles merged = merge(expression, elements, operator);
					elements.clear();
					elements.add(merged);
					operator = null;
					break;
				default:
					//equals方法提供Profiles接口的默认实现
					elements.add(equals(token));
			}
		}
		//对保存在elements中的多个Profiles做合并处理
		return merge(expression, elements, operator);
	}

	private static Profiles merge(String expression, List elements, @Nullable Operator operator) {
		//效验elements非空
		assertWellFormed(expression, !elements.isEmpty());
		//如果只有一个元素则返回该元素
		if (elements.size() == 1) {
			return elements.get(0);
		}
		Profiles[] profiles = elements.toArray(new Profiles[0]);
		//如果有多个则执行且处理或者或处理
		return (operator == Operator.AND ? and(profiles) : or(profiles));
	}

	private static void assertWellFormed(String expression, boolean wellFormed) {
		Assert.isTrue(wellFormed, () -> "Malformed profile expression [" + expression + "]");
	}

	private static Profiles or(Profiles... profiles) {
		//满足多个Profiles中的任何一个
		return activeProfile -> Arrays.stream(profiles).anyMatch(isMatch(activeProfile));
	}

	private static Profiles and(Profiles... profiles) {
		//满足所有的Profiles
		return activeProfile -> Arrays.stream(profiles).allMatch(isMatch(activeProfile));
	}

	private static Profiles not(Profiles profiles) {
		//对原Profiles对象做非处理
		return activeProfile -> !profiles.matches(activeProfile);
	}

	private static Profiles equals(String profile) {
		//默认的Profiles接口实现
		return activeProfile -> activeProfile.test(profile);
	}

	private static Predicate isMatch(Predicate activeProfile) {
		return profiles -> profiles.matches(activeProfile);
	}


	private enum Operator {AND, OR}


	private static class ParsedProfiles implements Profiles {

		private final String[] expressions;

		private final Profiles[] parsed;

		ParsedProfiles(String[] expressions, Profiles[] parsed) {
			this.expressions = expressions;
			this.parsed = parsed;
		}

		@Override
		public boolean matches(Predicate activeProfiles) {
			for (Profiles candidate : this.parsed) {
				//多个Profiles只有有一个满足则返回true
				if (candidate.matches(activeProfiles)) {
					return true;
				}
			}
			return false;
		}

		@Override
		public String toString() {
			return StringUtils.arrayToDelimitedString(this.expressions, " or ");
		}
	}

}

       结合测试用例借助Debug断点调试更容易理解ProfilesParser的实现

    @Test
	public void ofComplexExpression() {
        //最终的效果是Profiles必须是spring 和 framework组合,或者spring 和 java组合
		Profiles profiles = Profiles.of("(spring & framework) | (spring & java)");
		System.out.println("test spring");
		assertFalse(profiles.matches(activeProfiles("spring")));
		System.out.println("test spring framework");
		assertTrue(profiles.matches(activeProfiles("spring", "framework")));
		System.out.println("test spring java");
		assertTrue(profiles.matches(activeProfiles("spring", "java")));
		System.out.println("test java framework");
		assertFalse(profiles.matches(activeProfiles("java", "framework")));
	}

    
    private static Predicate activeProfiles(String... profiles) {
		return new MockActiveProfiles(profiles);
	}

	private static class MockActiveProfiles implements Predicate {

		private final List activeProfiles;

		MockActiveProfiles(String[] activeProfiles) {
			this.activeProfiles = Arrays.asList(activeProfiles);
		}

		@Override
        //最终传入test方法的profile的取值依次是spring,frame,spring,java
		public boolean test(String profile) {
			if (!StringUtils.hasText(profile) || profile.charAt(0) == '!') {
				throw new IllegalArgumentException("Invalid profile [" + profile + "]");
			}
            boolean result=this.activeProfiles.contains(profile);
			System.out.println("MockActiveProfiles-->"+profile+",result-->"+result);
			return result;
		}

	}

       测试结果如下:

test spring  
MockActiveProfiles-->spring,result-->true
MockActiveProfiles-->framework,result-->false  //(spring & framework)未匹配
MockActiveProfiles-->spring,result-->true
MockActiveProfiles-->java,result-->false       //(spring & java)未匹配
test spring framework
MockActiveProfiles-->spring,result-->true
MockActiveProfiles-->framework,result-->true  //(spring & framework)匹配,直接返回
test spring java
MockActiveProfiles-->spring,result-->true
MockActiveProfiles-->framework,result-->false
MockActiveProfiles-->spring,result-->true
MockActiveProfiles-->java,result-->true
test java framework
MockActiveProfiles-->spring,result-->false  //(spring & framework)中spring未匹配
MockActiveProfiles-->spring,result-->false  //(spring & java)中spring未匹配

 

你可能感兴趣的:(spring)