一、接口类继承图
二、接口类功能概述与实现
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
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
PropertySources接口继承自Iterable
重点关注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未匹配