Dubbo和Spring的融合

Dubbo和Spring的融合

通常,我們使用Dubbo的時(shí)候會(huì)創(chuàng)建如下的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
    <!-- 提供方應(yīng)用信息,用于計(jì)算依賴關(guān)系 -->
    <dubbo:application name="hello-world-app"  />
 
    <!-- 使用multicast廣播注冊(cè)中心暴露服務(wù)地址 -->
    <dubbo:registry address="multicast://127.0.0.1:1234" />
 
    <!-- 用dubbo協(xié)議在20880端口暴露服務(wù) -->
    <dubbo:protocol name="dubbo" port="20880" />
 
    <!-- 聲明需要暴露的服務(wù)接口 -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />
 
    <!-- 和本地bean一樣實(shí)現(xiàn)服務(wù) -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
</beans>

像dubbo:service這樣的標(biāo)簽是如何添加到spring并且被識(shí)別的呢?

答案是它使用了Spring的xsd schema文檔定義語(yǔ)言來(lái)實(shí)現(xiàn)的,首先我們自定義一套schema來(lái)熟悉一下Spring的可擴(kuò)展Schema。

分為五個(gè)步驟

1.設(shè)計(jì)配置屬性和Bean

2.編寫(xiě)xsd文件

3.使用NamespaceHandler和BeanDefinitionHandler來(lái)完成解析工作

4.配置spring.handlers和spring.schemas串聯(lián)這些類

5.在spring中使用這個(gè)bean

(1)定義一個(gè)User類:

@Data
public class User {

    String id;

    private String name;

    private String email;

    private int age;
}

(2)編寫(xiě)xsd文件

文件名稱為spring-test.xsd,名稱可以自定義

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.fanfte.com/schema/user"
        xmlns:tns="http://www.fanfte.com/schema/user" elementFormDefault="qualified">
    <element name="user">
        <complexType>
            <attribute name="id" type="string"/>
            <attribute name="age" type="int" />
            <attribute name="name" type="string" />
            <attribute name="email" type="string" />
        </complexType>
    </element>
</schema>

(3)使用NamespaceHandler和BeanDefinitionHandler來(lái)完成解析工作

首先編寫(xiě)bean解析器

public class UserBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {

    @Override
    protected Class<?> getBeanClass(Element element) {
        return User.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String id = element.getAttribute("id");
        String name = element.getAttribute("name");
        String email = element.getAttribute("email");
        Integer age = Integer.parseInt(element.getAttribute("age"));
        if(StringUtils.hasText(id)) {
            builder.addPropertyValue("id", id);
        }
        if(StringUtils.hasText(name)) {
            builder.addPropertyValue("name", name);
        }
        if(StringUtils.hasText(email)) {
            builder.addPropertyValue("email", email);
        }
        if(age != null) {
            builder.addPropertyValue("age", age);
        }
    }
}

再編寫(xiě)命名空間處理器:

public class UserNameSpaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

(4)配置spring.handlers和spring.schemas串聯(lián)這些類

再項(xiàng)目的classpath下的META-INF下配置兩個(gè)文件:

spring.handlers

http\://www.fanfte.com/schema/user=com.fanfte.rpc.spring.UserNameSpaceHandler

spring.schemas

http\://www.fanfte.com/schema/user.xsd=META-INF/spring-text.xsd

這里的路徑對(duì)應(yīng)了第二步xsd文件中的路徑,類名對(duì)應(yīng)了命名空間解析器的全路徑名com.fanfte.rpc.spring.UserNameSpaceHandler

(5)配置和加載bean到spring容器

classpath下新建一個(gè)application-tag.xml文件,內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:userTag="http://www.fanfte.com/schema/user" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.fanfte.com/schema/user http://www.fanfte.com/schema/user.xsd">

    <userTag:user id="userTag" name="userBean" email="fanfte@163.com" age="18"/>
    <!--<fanfteRPC:reference id="demoService" interface="com.fanfte.rpc.service.DemoService"></fanfteRPC:reference>-->
</beans>

xml中使用配置了的bean ,標(biāo)簽名稱為userTag,對(duì)應(yīng)了文件中的第四行的xmlns:userTag

最后,在main方法中使用這個(gè)bean

public class UserTagTest {

    @Autowired
    private DemoService demoService;

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:META-INF/application-tag.xml");
        User user = (User) context.getBean("userTag");
        System.out.println(user.getAge() + " " + user.getEmail() + " " + user.getName());
    }
}

這樣就使用了自定義的xsd來(lái)配置使用我們自定義的標(biāo)簽。dubbo也有一套自己的自定義標(biāo)簽。

Dubbo融合Spring

<1>首先我們看到DubboNamespaceHandler這個(gè)類內(nèi)部

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

}

這個(gè)類就是Dubbo的命名空間處理器,可以看到有10種的命名空間,而定義的配置屬性也定義在了xxxConfig和xxxBean里面,而解析器則使用了DubboBeanDefinitionParser和AnnotationBeanDefinitionParser兩種。

從這個(gè)類可以看到已經(jīng)完成了dubbo自定義schema完成了上面的第(1)和(3)步工作

<2>第二部我們可以在dubbo.xsd文件種發(fā)現(xiàn)

<xsd:element name="service" type="serviceType">
    <xsd:annotation>
        <xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation>
        <xsd:appinfo>
            <tool:annotation>
                <tool:exports type="org.apache.dubbo.config.ServiceConfig"/>
            </tool:annotation>
        </xsd:appinfo>
    </xsd:annotation>
</xsd:element>

<xsd:element name="reference" type="referenceType">
    <xsd:annotation>
        <xsd:documentation><![CDATA[ Reference service config ]]></xsd:documentation>
        <xsd:appinfo>
            <tool:annotation>
                <tool:exports type="org.apache.dubbo.config.ReferenceConfig"/>
            </tool:annotation>
        </xsd:appinfo>
    </xsd:annotation>
</xsd:element>

這里貼出來(lái)部分代碼,做了多種的xsd元素標(biāo)簽配置。

<3>spring.handlers

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

<4>spring.schemas

http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd

這兩個(gè)文件串聯(lián)了Dubbo的整個(gè)csd的解析

最后,在applicationContext這類xml文件中我們使用dubbo的標(biāo)簽讓spring管理我們定義的ServiceBean。

<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />

總結(jié):

1.通過(guò)上述5個(gè)步驟,我們實(shí)現(xiàn)了自定義的標(biāo)簽

2.通過(guò)觀察Dubbo源碼中的邏輯和配置,發(fā)現(xiàn)Dubbo從原理上也是這么實(shí)現(xiàn)它的自定義標(biāo)簽的,對(duì)于Spring的融合能夠完美支持。其實(shí)也就是利用了Spring的特性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,255評(píng)論 6 342
  • dubbo.xsd 文件說(shuō)明 當(dāng)我們要使用Dubbo進(jìn)行 配置時(shí),需要像下面那樣引入dubbo.xsd這個(gè)文件. ...
    Mis_Gtw閱讀 1,164評(píng)論 0 1
  • 叨叨 今天考慮了很久要不要寫(xiě)這篇文章。 距離《Dubbo源碼》系列的開(kāi)篇到現(xiàn)在已經(jīng)快兩個(gè)月時(shí)間了。當(dāng)時(shí)是想著工作上...
    Jackie_Zheng閱讀 1,190評(píng)論 0 1
  • 1.1 spring IoC容器和beans的簡(jiǎn)介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,846評(píng)論 2 22

友情鏈接更多精彩內(nèi)容