Dubbo入門


引子

趁着五一的功夫搞了搞Jenkins布署和Dubbo,面試的時候總會問用過Dubbo沒

前一家公司是做SpringCloud的微服務,所以就一直沒有了解過這個技術,寫個基礎入門的教程留待備忘

Dubbo是什么?

Dubbo是阿里巴巴開源的一款高性能Java RPC框架 (遠程服務調用的分布式框架)。旨在服務拆分后提供服務治理功能,目前已由Apache基金會維護

它提供了三大核心能力:面向接口的遠程方法調用智能容錯和負載均衡,以及服務自動注冊和發現

它的架構如圖:

了解SpringCloud的注冊中心Eureka或Consul就會發現其功能很接近:

  1. 服務提供者將服務地址與方法參數注冊到注冊中心
  2. 服務消費者啟動時訂閱服務提供者的服務地址,服務提供者變更時注冊中心將服務地址列表發給消費者
  3. 通過得到的地址調用服務接口返回結果,包含負載均衡,失敗則調用其它
  4. 異步服務調用計數,用於監控各服務調用情況,如,調用時間/調用次數

其中第3步與Eureka和Consul的Http調用不同,Dubbo底層調用使用的是Netty建立的NIO通道,其高性能就在於此,即沒有Http調用頻繁開啟關閉通道維護session和很多為了標識客戶端狀態的信息,通過非阻塞(NIO)長連接直接拿到業務數據

HelloWorld 01

以官方推薦Zookeeper注冊中心為例,代碼在https://github.com/HellxZ/DubboLearn.git 的master分支上

啟動Zookeeper注冊中心

下載最新的Zookeeper:Download

解壓並進入解壓縮后的文件夾下的conf目錄,復制zoo_sample.cfg,創建新的配置

cd zookeeper-3.4.14/conf
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg

編輯zoo.cfg,按照Zookeeper官方推薦修改dataDir,選擇自己想要的路徑

保存修改退出

進入可執行文件目錄,啟動Zookeeper服務端

cd ../bin
./zkServer.sh start #啟動服務端

查看啟動狀態./zkServer.sh status,如下圖即正常啟動成功

查看Zookeeper日志tail -f zookeeper.out,在bin路徑下的zookeeper.out,不要關閉終端方便觀察

創建服務提供者

思路:使用兩個Spring項目分別代表提供者與消費者,使用Dubbo注冊到注冊中心,不使用Tomcat以求配置最簡化,展示xml全配置方式是如何操作

新建個Maven項目ServiceProvider,pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>XmlConfiguration</artifactId>
        <groupId>com.cnblogs.hellxz</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ServiceProvider</artifactId>

    <properties>
        <spring.version>4.1.4.RELEASE</spring.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j.version>1.7.7</slf4j.version>
    </properties>

    <dependencies>
        <!--spring 核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring上下文包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 為了方便進行單元測試,添加spring-test包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加spring-web包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring切面包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加aspectjweaver包 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>
        <!-- 添加servlet3.0核心包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!--日志包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- 阿里巴巴fastjson包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>
        <!--阿里巴巴dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>serviceProvider</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

創建個服務接口與實現類

package com.cnblogs.hellxz.service;

public interface IProviderService {
    String call();
}
package com.cnblogs.hellxz.service.impl;

import com.cnblogs.hellxz.service.IProviderService;

public class ProviderServiceImpl implements IProviderService {
    @Override
    public String call() {
        //為了演示清楚,打印紅色的輸出,並非錯誤信息
        System.err.println("服務調用成功");
        return "Call service-provider success!";
    }
}

在resources下新建provider.xml,內容如下:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://code.alibabatech.com/schema/dubbo
    http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
    <!--僅保留核心配置-->

    <!--包掃描-->
    <context:component-scan base-package="com.cnblogs.hellxz"/>

    <!-- 提供方應用信息,用於計算依賴關系,請勿與其他服務名稱相同 -->
    <dubbo:application name="service-provider"/>
    <!-- 使用zookeeper注冊中心暴露服務地址,地址為zookeeper所在地址 -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>

    <!--指定要暴露的實現類-->
    <bean id="providerService" class="com.cnblogs.hellxz.service.impl.ProviderServiceImpl"/>
    <!--提供服務實現遠程調用,消費者只需要有相同的接口即可調用-->
    <dubbo:service interface="com.cnblogs.hellxz.service.IProviderService" ref="providerService"/>
</beans>

log4j.properties

#日志輸出級別
log4j.rootLogger=INFO,stdout
#設置stdout的日志輸出控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#輸出日志到控制台的方式,默認為System.out
log4j.appender.stdout.Target=System.out
#設置使用靈活布局
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#靈活定義輸出格式
log4j.appender.stdout.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH:mm:ss}] %l %m %n

項目啟動類ProviderMain

package com.cnblogs.hellxz;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;

/**
 * 服務提供者啟動類
 */
public class ProviderMain {
    public static void main(String[] args) throws IOException {
        //讀取配置文件,初始化Spring容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("provider.xml");
        //保持線程存活
        System.in.read();
    }
}

啟動項目,我們觀察到Zookeeper.out有日志出現了,即注冊成功

創建服務消費者

結構如圖:

pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>XmlConfiguration</artifactId>
        <groupId>com.cnblogs.hellxz</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>Consumer</artifactId>

    <properties>
        <spring.version>4.1.4.RELEASE</spring.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j.version>1.7.7</slf4j.version>
    </properties>

    <dependencies>
        <!--spring 核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring上下文包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 為了方便進行單元測試,添加spring-test包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加spring-web包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring切面包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加aspectjweaver包 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>

        <!-- log4j日志包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- 阿里巴巴fastjson包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>
        <!--阿里巴巴dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.5</version>
        </dependency>
        <!--解決Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.api.CuratorWatcher-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!--解決java.lang.NoClassDefFoundError: io/netty/channel/nio/NioEventLoopGroup-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>consumer</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

pom文件中有些依賴沒有會導致一些錯誤,本人已經將依賴添加的理由寫上了,可以去除測試是否如實

log4j配置同提供者項目配置,如下是consumer.xml

<?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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://code.alibabatech.com/schema/dubbo
    http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>
    <!--僅保留核心配置-->

    <!--包掃描-->
    <context:component-scan base-package="com.cnblogs.hellxz"/>

    <!-- 提供方應用信息,用於計算依賴關系,請勿與提供方相同 -->
    <dubbo:application name="service-consumer">
        <dubbo:parameter key="qos.enable" value="true"/>
        <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
        <!--
        報錯java.net.BindException: 地址已在使用
        問題出現的原因:
            consumer啟動時qos-server也是使用的默認的22222端口,但是這時候端口已經被provider給占用了,所以才會報錯的。
        解決:指定新端口號
        -->
        <dubbo:parameter key="qos.port" value="33333"/>
    </dubbo:application>

    <!-- 
		指定注冊中心使用的協議,這里使用zookeeper實現,地址為zookeeper的ip與端口
		如果不指定protocol,address可寫為 address="zookeeper://127.0.0.1:2181"
	-->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>

    <!-- 
		引用——通過rpc調用注冊服務id為providerService的服務,通過這個設置我們就可以像調用本地方法一樣調用
        需要注意的是:接口的包結構與類名,id均要與服務提供者完全相同,本人已測試
     -->
    <dubbo:reference interface="com.cnblogs.hellxz.service.IProviderService" id="providerService"/>
</beans>

調用服務提供者的方法接口的包路徑、類名、方法名須與提供者完全相同

創建消費者項目啟動類,演示一次調用。啟動main方法

package com.cnblogs.hellxz;

import com.cnblogs.hellxz.service.IProviderService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 消費者啟動類
 */
public class ConsumerMain {
    public static void main(String[] args) {
        //初始化spring容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("consumer.xml");
        //取出容器中的bean
        IProviderService providerService = (IProviderService)ctx.getBean("providerService");
        //打印調用結果 為了演示清楚,打印紅色的輸出,並非錯誤信息
        System.err.println(providerService.call());
    }
}

如圖,調用成功

這里我們發現:如果我們調用一個方法,必須要寫一個重復的接口類,如果服務提供者變更就可能出現不一致的問題,所以在下一個demo中把公共的接口抽取成一個模塊,順便把注解使用寫在一起了

Hello World 02

與上一個demo區別:包含注解使用、抽取公共接口模塊,代碼在https://github.com/HellxZ/DubboLearn.git 的xml-base01分支上

這個分支是從上一個代碼中checkout出來的,所以有部分全配置設置,這里只需關心帶annotation的xml和啟動方法就好

公共接口

與上個demo中服務接口相同,不上代碼了,可以參考代碼

服務提供者

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>XmlConfiguration</artifactId>
        <groupId>com.cnblogs.hellxz</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ServiceProvider</artifactId>

    <properties>
        <spring.version>4.1.4.RELEASE</spring.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j.version>1.7.7</slf4j.version>
    </properties>

    <dependencies>
        <!--公用接口-->
        <dependency>
            <groupId>com.cnblogs.hellxz</groupId>
            <artifactId>CommonInterface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--spring 核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring上下文包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 為了方便進行單元測試,添加spring-test包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加spring-web包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring切面包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加aspectjweaver包 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>
        <!-- 添加servlet3.0核心包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!--日志包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- 阿里巴巴fastjson包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>
        <!--阿里巴巴dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.5</version>
        </dependency>
        <!--解決使用注解出現ClassNotFoundException: com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor-->
        <dependency>
            <groupId>com.alibaba.spring</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>1.0.2</version>
        </dependency>
        <!--zookeeper包-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>serviceProvider</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

provider-annotation-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://code.alibabatech.com/schema/dubbo
    http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
>
    <!--僅保留核心配置-->

    <!--開啟切面編程自動代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!--掃描注解生成bean-->
    <context:annotation-config/>
    <!--包掃描-->
    <context:component-scan base-package="com.cnblogs.hellxz"/>

    <!-- 提供方應用信息,用於計算依賴關系,請勿與其他服務名稱相同 -->
    <dubbo:application name="service-provider"/>
    <!-- 使用zookeeper注冊中心暴露服務地址,地址為zookeeper所在地址 -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>

    <dubbo:annotation package="com.cnblogs.hellxz"/>
</beans>

log4j日志配置不變,下面是ProviderMain

package com.cnblogs.hellxz;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

/**
 * 服務提供者啟動類
 */
public class ProviderMain {

    /**
     * 以全配置方式啟動spring容器,提供服務
     */
    @Test
    public void testFullXmlConfig() {
        initSpringContextWithConfigXml("provider-full-xml-config.xml");
    }

    /**
     * 使用配置方式開啟注解,啟動spring容器,提供服務
     */
    @Test
    public void testAnnotation() {
        initSpringContextWithConfigXml("provider-annotation-config.xml");
    }

    /**
     * 使用配置文件啟動spring容器
     *
     * @param springConfigXmlName 配置文件在classPath下的路徑名稱
     */
    private void initSpringContextWithConfigXml(String springConfigXmlName) {
        //讀取配置文件,初始化Spring容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext(springConfigXmlName);
        try {
            //保持線程存活,輸入任意字符回車停止
            System.in.read();
        } catch (IOException e) {
            //僅作演示不處理
            e.printStackTrace();
        }
    }
}

ProviderServiceImpl相對於Hello World 01中只是加了個@Service注解,但是注意這個注解是dubbo包下的

package com.cnblogs.hellxz.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.cnblogs.hellxz.service.IProviderService;

@Service
public class ProviderServiceImpl implements IProviderService {

    @Override
    public String call() {
        //為了演示清楚,打印紅色的輸出,並非錯誤信息
        System.err.println("服務調用成功");
        return "Call service-provider success!";
    }
}

啟動testAnnotation方法即可啟動服務

請先關掉上個demo中啟動的方法

服務消費者

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>XmlConfiguration</artifactId>
        <groupId>com.cnblogs.hellxz</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>Consumer</artifactId>

    <properties>
        <spring.version>4.1.4.RELEASE</spring.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j.version>1.7.7</slf4j.version>
    </properties>

    <dependencies>
        <!--spring 核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring上下文包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 為了方便進行單元測試,添加spring-test包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加spring-web包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring切面包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--添加aspectjweaver包 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.5</version>
        </dependency>

        <!-- log4j日志包 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- 阿里巴巴fastjson包 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>
        <!--阿里巴巴dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.5</version>
        </dependency>
        <!--解決Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.api.CuratorWatcher-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!--解決java.lang.NoClassDefFoundError: io/netty/channel/nio/NioEventLoopGroup-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
        <!--添加公用接口模塊-->
        <dependency>
            <groupId>com.cnblogs.hellxz</groupId>
            <artifactId>CommonInterface</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--解決使用注解出現ClassNotFoundException: com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor-->
        <dependency>
            <groupId>com.alibaba.spring</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>1.0.2</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>consumer</finalName>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

consumer-annotation-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://code.alibabatech.com/schema/dubbo
    http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
>
    <!--僅保留核心配置-->

    <!--開啟切面編程自動代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!--包掃描-->
    <context:component-scan base-package="com.cnblogs.hellxz"/>
    <!--掃描注解生成bean-->
    <context:annotation-config/>

    <!-- 提供方應用信息,用於計算依賴關系,請勿與提供方相同 -->
    <dubbo:application name="service-consumer">
        <dubbo:parameter key="qos.enable" value="true"/>
        <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
        <!--
        報錯java.net.BindException: 地址已在使用
        問題出現的原因:
            consumer啟動時qos-server也是使用的默認的22222端口,但是這時候端口已經被provider給占用了,所以才會報錯的。
        解決:指定新端口號
        -->
        <dubbo:parameter key="qos.port" value="33333"/>
    </dubbo:application>

    <!-- 使用zookeeper注冊中心暴露服務地址,地址為zookeeper所在地址 -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>

    <dubbo:annotation package="com.cnblogs.hellxz"/>
</beans>

需要有一個bean在spring容器中對應Dubbo引用的接口上

package com.cnblogs.hellxz.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.cnblogs.hellxz.service.IProviderService;
import org.springframework.stereotype.Service;

/**
 * 這個類主要作用就是dubbo引用的接口與providerService這個bean名稱作綁定
 * 在全xml配置方式中無需存在,注意這回的@Service注解是spring的
 */
@Service("providerService")
public class ProviderServiceImpl implements IProviderService {

    @Reference
    private IProviderService iProviderService;

    @Override
    public String call() {
        return iProviderService.call();
    }
}

注意事項:

  1. 這回的@Service注解是spring的
  2. 使用Springmvc時無需再包這一層,在@Controller或@RestController的類中直接寫@Reference就可以了

貼出啟動方法,這次用的是Junit測試的

    @Test
    public void testAnnotationConfig() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer-annotation-config.xml");
        IProviderService providerService = (IProviderService) context.getBean("providerService");
        System.err.println(providerService.call());
    }

測試結果與Demo01相同

報錯與解決

1.在注冊中心找不到對應的服務

java.lang.IllegalStateException: Failed to check the status of the service *.*.*.xxService . No provider available for the service *.*.*.xxService

這個錯誤原因是服務端沒有將xxService服務注冊到注冊中心,原因無非三種

  1. 沒加com.alibaba.dubbo.config.annotation包下的@Service注解或引錯包;
  2. 服務端沒啟動起來,檢查服務端狀態
  3. 服務端沒注冊到注冊中心,檢查服務端測試中心配置

2. 無法連接到注冊中心

  1. 檢查Zookeeper是否正常運行
  2. 檢查報錯項目的注冊中心地址配置

3. ClassNotFound異常

3.1
Caused by: java.lang.ClassNotFoundException: org.apache.curator.framework.api.CuratorWatcher

添加依賴

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.7.0</version>
        </dependency>
3.2
ClassNotFoundException: com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor

添加依賴

        <dependency>
            <groupId>com.alibaba.spring</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>1.0.2</version>
        </dependency>

4. NoClassDefFoundError錯誤

java.lang.NoClassDefFoundError: io/netty/channel/nio/NioEventLoopGroup

添加依賴

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>

5. java.net.BindException: 地址已在使用

    <!-- 提供方應用信息,用於計算依賴關系,請勿與提供方相同 -->
    <dubbo:application name="service-consumer">
        <dubbo:parameter key="qos.enable" value="true"/>
        <dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
        <!--
        報錯java.net.BindException: 地址已在使用
        問題出現的原因:
            consumer啟動時qos-server也是使用的默認的22222端口,但是這時候端口已經被provider給占用了,所以才會報錯的。
        解決:指定新端口號
        -->
        <dubbo:parameter key="qos.port" value="33333"/>
    </dubbo:application>

最后

與SpringBoot的集成的版本后續會開發到新分支下,本文僅介紹Dubbo的架構與基礎用法

歡迎關注點贊評論轉載,比B站多一連 😃,您的支持就是我的動力

本文為實操筆記,轉載請注明出處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM