Dubbo入门
引子
趁着五一的功夫搞了搞Jenkins布署和Dubbo,面试的时候总会问用过Dubbo没
前一家公司是做SpringCloud的微服务,所以就一直没有了解过这个技术,写个基础入门的教程留待备忘
Dubbo是什么?
Dubbo是阿里巴巴开源的一款高性能Java RPC框架 (远程服务调用的分布式框架)。旨在服务拆分后提供服务治理功能,目前已由Apache基金会维护
它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
它的架构如图:
了解SpringCloud的注册中心Eureka或Consul就会发现其功能很接近:
- 服务提供者将服务地址与方法参数注册到注册中心
- 服务消费者启动时订阅服务提供者的服务地址,服务提供者变更时注册中心将服务地址列表发给消费者
- 通过得到的地址调用服务接口返回结果,包含负载均衡,失败则调用其它
- 异步服务调用计数,用于监控各服务调用情况,如,调用时间/调用次数
其中第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(); } }
注意事项:
- 这回的@Service注解是spring的
- 使用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服务注册到注册中心,原因无非三种
- 没加com.alibaba.dubbo.config.annotation包下的@Service注解或引错包;
- 服务端没启动起来,检查服务端状态
- 服务端没注册到注册中心,检查服务端测试中心配置
2. 无法连接到注册中心
- 检查Zookeeper是否正常运行
- 检查报错项目的注册中心地址配置
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站多一连 😃,您的支持就是我的动力
本文为实操笔记,转载请注明出处
本文作者:东北小狐狸
本文链接:https://www.cnblogs.com/hellxz/p/10808753.html
版权声明:本作品采用自由转载-非商用-非衍生-保持署名 (CC BY-NC-ND 3.0)许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步