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

ServiceBeanNameBuilder

用以构建 ServcieBean 的 name,一个常见的建造者模式。ServcieBean 的 name主要有interfaceClassName、version、group组成,interfaceClassName是必有,后两者可选,比如"ServiceBean:org.com.Demo:1.0.0:lala"该类含有的属性如下:

private static final String SEPARATOR = ":";

// Required
private final String interfaceClassName;

private final Environment environment;

// Optional
private String version;

private String group;

提供了一些create静态方法用以创建ServiceBeanNameBuilder实例,然后链式调用其group(x)、version(x)方法,最后build方法进行构建。eg : ServiceBeanNameBuilder.create(x).group(x).version(x).build() 。下面看create方法。getAnnotationAttributes是spring包的AnnotationUtils类的方法,返回值为AnnotationAttributes,就是把@Service、@Reference注解的属性值填充到返回的AnnotationAttributes对象中。

public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
    return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
}

public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {
    return new ServiceBeanNameBuilder(interfaceClass, environment);
}

public static ServiceBeanNameBuilder create(Service service, Class<?> interfaceClass, Environment environment) {
    return create(getAnnotationAttributes(service, false, false), interfaceClass, environment);// 调第一个
}

public static ServiceBeanNameBuilder create(Reference reference, Class<?> interfaceClass, Environment environment) {
    return create(getAnnotationAttributes(reference, false, false), interfaceClass, environment);// 调第一个
}

三个构造方法如下,这里说下最后一个构造方法。第一个参数是spring的类(前面create方法调用getAnnotationAttributes方法的返回值传入来的)。第一步调用了DubboAnnotationUtils#resolveInterfaceName方法,该方法内部主要是获取注解的属性集合(attributes)中属性名为interfaceClass的值,可以看后面test程序的@Service(interfaceClass = DemoService.class…);既然有attributes,肯定含有group和version信息,顺带取出即可。

private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
    this(interfaceClass.getName(), environment);// 调用下面的
}

private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {
    this.interfaceClassName = interfaceClassName;
    this.environment = environment;
}

private ServiceBeanNameBuilder(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
    this(resolveInterfaceName(attributes, defaultInterfaceClass), environment);// 调用上面的
    this.group(getAttribute(attributes,"group"));
    this.version(getAttribute(attributes,"version"));
}

如下,两个方法,建造者模式的惯用法,用以链式调用,给builder本身(非目标对象)的属性赋值。

public ServiceBeanNameBuilder group(String group) {
    this.group = group;
    return this;
}

public ServiceBeanNameBuilder version(String version) {
    this.version = version;
    return this;
}

build方法,生成目标对象,这里目标对象很简单,就是String。正常的实体类型比如Person,build内部会创建Person实例,然后挨个赋值到person对象并返回。build方法逻辑这样的,所有的name都是以"ServiceBean"开头,然后追加interfaceClassName、version、group信息,中间以SEPARATOR即:分割(在append方法内部),最后一个是防止有placeHolder,利用Environment解析填充即可,比如"ServiceBean:org.com.Demo:1.0.0:${group}"。

public String build() {
    StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
    // Required
    append(beanNameBuilder, interfaceClassName);
    // Optional
    append(beanNameBuilder, version);
    append(beanNameBuilder, group);
    // Build and remove last ":"
    String rawBeanName = beanNameBuilder.toString();
    // Resolve placeholders
    return environment.resolvePlaceholders(rawBeanName);
}

ServiceBeanNameBuilderTest

测试程序很简单。prepare方法就是MockEnvironment,之前讲过了, @Reference注解里面正好有${dubbo.version}这个,MockEnvironment就可以解析并替换为"1.0.0"

两个测试方法分别测试 类上的@Service注解和INTERFACE_CLASS属性上的 @Reference注解,两个测试方法使用ServiceBeanNameBuilder.create + build完成String ServiceBeanName 的构建 。注意两个注解的interfaceClass、group、version三个属性就好。(注意ServiceBeanNameBuilder#build()方法最后会调用environment的resolvePlaceholders方法,将@Reference注解的${dubbo.version}属性值替换为"1.0.0")

@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
        application = "application", module = "module", registry = {"1", "2", "3"})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ServiceBeanNameBuilderTest {

    @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}",
            application = "application", module = "module", registry = {"1", "2", "3"})
    static final Class<?> INTERFACE_CLASS = DemoService.class;

    static final String GROUP = "DUBBO";

    static final String VERSION = "1.0.0";

    private MockEnvironment environment;

    @BeforeEach
    public void prepare() {
        environment = new MockEnvironment();
        environment.setProperty("dubbo.version", "1.0.0");
    }

    @Test
    public void testServiceAnnotation() {
        Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class);
        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment);
        Assertions.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
                builder.build());

    }

    @Test
    public void testReferenceAnnotation() {
        Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class);
        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment);
        Assertions.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
                builder.build());
    }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值