dubbo源码解析:Config-Spring——AnnotationPropertyValuesAdapter

AnnotationPropertyValuesAdapter

AnnotationPropertyValuesAdapter

该类实现PropertyValues接口,这个接口主要是存放一个Bean的属性值集合,就可以理解为一个map。

内部有一个PropertyValues delegate属性。有三个重载的构造函数。说一下参数最全的两个构造函数

public AnnotationPropertyValuesAdapter(Annotation annotation, PropertyResolver propertyResolver,
                                       boolean ignoreDefaultValue, String... ignoreAttributeNames) {
    this.delegate = new MutablePropertyValues(getAttributes(annotation, propertyResolver, ignoreDefaultValue, ignoreAttributeNames));
}

getAttributes是AnnotationUtils类的一个方法(AnnotationUtils是阿里com.alibaba.spring.util包的内容),getAttributes方法返回类型为Map<String, Object>,该方法的主要作用就是解析注解的属性kv值并填充到返回的map中,ignoreDefaultValue和ignoreAttributeNames是配合使用的,如果前者为true,那么后者就可以提供想要忽略的属性值,这样最终就不会填充到返回的map中。new MutablePropertyValues接受的类型为map,MutablePropertyValues是PropertyValues一个实现类。

这也是这个类被称之为Annotation + Adapter的原因,spring没有提供注解解析并映射为PropertyValues的实现类,所以搞了一个适配器,利用AnnotationUtils#getAttributes解析并映射并构建MutablePropertyValues。


public AnnotationPropertyValuesAdapter(Map<String, Object> attributes, PropertyResolver propertyResolver,
                                       String... ignoreAttributeNames) {
    this.delegate = new MutablePropertyValues(getAttributes(attributes, propertyResolver, ignoreAttributeNames));
}

这个重载构造函数,第一个参数不是注解实例,而直接是一个map,然后依然调用阿里的重载的AnnotationUtils#getAttributes方法,整体逻辑和前面说的构造函数落差不多,毕竟前面的注解实例解析后也是一个和(该构造函数)第一个参数类似的map。


实现PropertyValues接口需要重写如下方法,这些方法就和map的kv存取差不多。

@Override
public PropertyValue[] getPropertyValues() {
    return delegate.getPropertyValues();
}

@Override
public PropertyValue getPropertyValue(String propertyName) {
    return delegate.getPropertyValue(propertyName);
}

@Override
public PropertyValues changesSince(PropertyValues old) {
    return delegate.changesSince(old);
}

@Override
public boolean contains(String propertyName) {
    return delegate.contains(propertyName);
}

@Override
public boolean isEmpty() {
    return delegate.isEmpty();
}

AnnotationPropertyValuesAdapterTest

该测试类主要测试了上面的AnnotationPropertyValuesAdapter,内部使用了spring的相关api:包括MockEnvironment、 ReflectionUtils.findField、AnnotationUtils.getAnnotation、DataBinder、DefaultConversionService等。

(1)首先搞了一个MockEnvironment,这个是spring的 Environment 接口子类,Environment主要是解析替换placeHolder的,就是那些 x x 的 。 然 后 直 接 k v 方 式 存 入 , 这 样 遇 到 {xx}的。然后直接kv方式存入,这样遇到 xxkv{url}的就会替换为"1.0.0"。

MockEnvironment mockEnvironment = new MockEnvironment();
mockEnvironment.setProperty("version", "1.0.0"); 
mockEnvironment.setProperty("url", "   dubbo://localhost:12345");

(2)使用spring的ReflectionUtils.findField、AnnotationUtils.getAnnotation现有工具类来获取TestBean类的demoService方法上的Reference注解(TestBean类见最后)。如下,注意@Reference标记为废弃了,最新版本使用@DubboService和@DubboReference。

Field field = ReflectionUtils.findField(TestBean.class, "demoService");
Reference reference = AnnotationUtils.getAnnotation(field, Reference.class);

(3)使用spring的DataBinder,构建DataBinder对象并指定要绑定到的目标对象ReferenceBean实例、指定忽略的填充字段、类型转化器DefaultConversionService、PropertyValues实例、最后一步调用dataBinder.bind(propertyValues);即可把PropertyValues的值填充到实例中(当然bind内部逻辑涉及到哪些属性忽略,以及特定类型属性的值转化,提供的两个类型转化器,用了spring的StringUtils#arrayToCommaDelimitedString以及dubbo的CollectionUtils.toStringMap),如下

ReferenceBean referenceBean = new ReferenceBean();
DataBinder dataBinder = new DataBinder(referenceBean);

dataBinder.setDisallowedFields("application", "module", "consumer", "monitor", "registry"); 

DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter((Converter<String[], String>) source -> arrayToCommaDelimitedString(source));
conversionService.addConverter((Converter<String[], Map<String, String>>) source -> CollectionUtils.toStringMap(source));
dataBinder.setConversionService(conversionService);

AnnotationPropertyValuesAdapter propertyValues = new AnnotationPropertyValuesAdapter(reference, mockEnvironment);
dataBinder.bind(propertyValues);

TestBean如下

private static class TestBean {

    @Reference(
            interfaceClass = DemoService.class, interfaceName = "com.alibaba.dubbo.config.spring.api.DemoService",
            version = "${version}", group = "group",
            url = "${url}  ", client = "client", generic = true, injvm = true,
            check = false, init = true, lazy = true, stubevent = true,
            reconnect = "reconnect", sticky = true, proxy = "javassist", stub = "stub",
            cluster = "failover", connections = 1, callbacks = 1, onconnect = "onconnect",
            ondisconnect = "ondisconnect", owner = "owner", layer = "layer", retries = 1,
            loadbalance = "random", async = true, actives = 1, sent = true,
            mock = "mock", validation = "validation", timeout = 2, cache = "cache",
            filter = {"default", "default"}, listener = {"default", "default"}, parameters = {"key1", "value1"}, application = "application",
            module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry1", "registry2"}
    )
    private DemoService demoService;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值