在 Spring 中如何扩展现有类的功能 ?

在 spring 中,我们常常会基于现有的代码来扩展之前的功能,或者换一个实现的方式

1. 原有的功能

在这里基于之前的功能获取属性来继续深入。

大致代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Slf4j
@Order
public class CompositePropertySources implements PropertySources {
	
	private final MutablePropertySources mutablePropertySources = new MutablePropertySources();
	
	public CompositePropertySources(List<AbstractSimplePropertySource> sources) {
		if (sources == null) return;
		AnnotationAwareOrderComparator.sort(sources);
		for (AbstractSimplePropertySource source : sources) {
			mutablePropertySources.addLast(source);
		}
	}
	
	public boolean containsProperty(String name) {
		return stream().anyMatch(p -> p.containsProperty(name));
	}
	
	public String getProperty(String name) {
		return isBlank(name) ? name : getProperty(name, null);
	}
	
	public String getProperty(String propertyName, String defaultValue) {
		String value = null;
		for (PropertySource<?> ps : mutablePropertySources) {
			value = (String) ps.getProperty(propertyName);
			if (value != null) {
				return value;
			}
		}
		return defaultValue;
	}
	
	public Map<String, String> getProperties(String... propertyNames) {
		if (propertyNames != null) {
			Map<String, String> map = new HashMap<>();
			for (String key : propertyNames) {
				map.put(key, getProperty(key, null));
			}
			return map;
		}
		return null;
	}
}

2. 新的需求

由于之前的功能是根据 key 来获取 value的,而现在需要根据业务编号和 key 来获取 value

  • 先根据 businType.key 来获取 value
  • 如果结果不是 null,则返回
  • 如果结果是 null, 再根据 key 来获取 value

根据上面的描述,也就是优先取业务类型的配置

因为我们的功能实际上在上一篇就已经完成了,所以在这一节中,只需要扩展原有的功能就行了。

这里我使用 BeanPostProcessor 来进行扩展,选择这个类的原因是原有的 bean 已经生成了,无需更改 bean 定义.

实现如下:

  • 判断 bean 是否为 CompositePropertySources 的实例
  • 使用 ProxyCompositePropertySources 对象来代替原有的类
  • 使用 propertyNamesFunction 来分隔 propertyName
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@Component
public class CompositePropertySourcesBeanPostProcessor implements BeanPostProcessor {

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof CompositePropertySources) {
      return new ProxyCompositePropertySources((CompositePropertySources) bean);
    }

    return bean;
  }

  protected static class ProxyCompositePropertySources extends CompositePropertySources {

    private final CompositePropertySources compositePropertySources;

    public ProxyCompositePropertySources(CompositePropertySources compositePropertySources) {
      super(null);
      this.compositePropertySources = compositePropertySources;
    }

    @Override
    public String getProperty(String propertyName, String defaultValue) {
      String[] propertyNames = propertyNamesFunction.apply(propertyName);

      for (String p : propertyNames) {
        String v = compositePropertySources.getProperty(p);
        if (v != null) {
          return v;
        }
      }

      return defaultValue;
    }

    @Override
    public boolean containsProperty(String propertyName) {
      String[] propertyNames = propertyNamesFunction.apply(propertyName);

      for (String p : propertyNames) {
        boolean contains = compositePropertySources.containsProperty(p);
        if (contains) {
          return true;
        }
      }

      return false;
    }
  }

  private static final Function<String, String[]> propertyNamesFunction = (propertyName) -> {
    if (propertyName == null) {
      return new String[0];
    }

    propertyName = propertyName.trim();

    if (propertyName.contains(".")) {
      return new String[]{propertyName, propertyName.substring(propertyName.lastIndexOf(".") + 1)};
    }

    return new String[]{propertyName};
  };
}

3. 完整代码实现

github 地址

0%