您的位置:首页 > 其它

简单使用dubbo以及坑说明

2018-03-21 18:59 621 查看
网上攻略很多,但是很多细节和原因解释的有点不足,为了完善一些细节就有了此文。
准备工作:
    一台linux系统的电脑,用以支持zookeeper服务注册中心(当然也可以用数据库来做这件事,这个以后有空在补充,这里先zookeeper)
    一台跑服务的电脑(也可以本地服务连接本地)
基本原理:
    注册中心启动->监听接口
    提供者启动->按照配置向注册中心注册自己的服务和端口
    消费者启动->向注册中心索取自己需要的服务的提供者信息
注意:这里的消费者并不一定是用户,而是服务的调用者(或者说是业务逻辑)。
    其实本质是一种远程执行的动态代理(所以实现方法如果使用了一些本地类是需要实现序列化接口的,不然无法通过网络传递)

一:zookeeper配置

流程:
1.下载zookeeper
2.解压到你想放的位置(比如/usr/local/services/),进入config下修改zoo.cfg(一开始没有这文件,直接复制一份给的样本zoo_sample.cfg改名即可)
坑:
0.请使用 ./zkServer.sh -status确认服务真的启动了!!
1.请确认有安装jdk
2.如果启动还是失败请看看zookeeper根目录下的.out文件,如果启动失败又没有此文件,请参考1
启动成功后记住自己配置的端口号(默认2181)
3.zookeeper启动完毕后,请在其他的机器上用zkCli登录此端口,确认连接可用,如果提示授权错误(authorication)之类的,请直接关掉防火墙再次尝试,确认是否是端口被阻止。
二:(可选)启动一个dubbo-admin用于可视化管理注册和消费
流程我就不赘述了。其实就是个dubbo consumer,只不过不调用任何服务,只看。所以会需要配置,配置比较简单,dubbo.registry.address=zookeeper://192.168.2.115:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest填你自己的zookeeper 的ip和端口即可。账号密码改不改随意。
坑:
1.如果用网上下载的war包无法启动你的tomcat,多半是因为此war包和tomcat版本,jdk版本兼容的问题。建议直接去git上获取源代码,然后自行用本地的jdk版本编译。(我用的这个https://github.com/dangdangdotcom/dubbox,build完成后dubbo-admin下的out内项目放入tomcat即可)
三:编写provider
吐槽:dubbo已经和spring耦合了,框架层面的耦合,说实话非常不应该,这造成了后续一大堆的兼容性坑。
流程:
1.建一个maven项目,pom文件配置来处理依赖
这个依赖只能保证jdk1.8以及tomcat9的运行有效。由于多个框架重度耦合,各种冲突,如果你不需要某个版本的spring ,建议善用exclusions,同理还有log4j等等乱七八糟的jar包冲突(maven的依赖冲突的处理逻辑真心差)
<?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"> <modelVersion>4.0.0</modelVersion>

<groupId>test.dubbo</groupId>
<artifactId>test-dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>com.alibaba</groupId>

4000
<artifactId>dubbo</artifactId>
<version>2.6.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
<exclusions>
<exclusion>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
build完毕后基础依赖就完成了。
坑:
如果最后运行时提示缺什么类,请善用ide的输出目录时的lib选定,一点一点的排除无用jar包,如果你弄不清楚缺少的class是哪个jar包的,请安装反编译工具,然后到根错误下搜索对应的import目录,然后去maven上搜索
2.编写interface
请注意,这是整个dubbo的核心,服务类和消费者是依靠接口交互,而不是配置的name或者id什么的/**
* dubbo向注册中心注册的核心是接口
* 无论消费者还是提供者,都是通过接口来进行匹配的
*/

public interface ICaculator {

public int sum(int a ,int b);
public int substract(int minued, int subtrahend);

}3.编写实现类public class caculator implements ICaculator{
@Override
public int sum(int a, int b) {
System.out.println("调用加法服务");
return a+b;
}

@Override
public int substract(int minued, int subtrahend) {
System.out.println("调用减法服务");
return minued-subtrahend;
}

}注意,也可以在此处注解来进行dubbo的Interface指明,这里我通过配置文件指明了,不需要冗余配置
@Component("service")
@Service
4.配置
先是dubbo-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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 服务提供方的信息,命名空间,用于服务注册中心对依赖关系的计算 -->
<dubbo:application name="dubboProviderMain" />

<!-- 注册中心地址 -->
<dubbo:registry address="zookeeper://192.168.2.115:2181" />
<!-- 强制设定用dubbo协议在20881端口暴露服务,不写则默认20880-->
<dubbo:protocol name="dubbo" port="20881" />

<!-- 实现服务的类,此类在消费者处被动态代理出来,所以其引用的类需要引用序列化接口 -->
<bean id="linkToImpl" class="me.cicyer.test.dubbo.impl.caculator" />
<!-- 声明需要暴露的服务接口,注意这个ref只是用来在xml里指向bean的,与具体服务注册毫无关系 -->
<dubbo:service interface="me.cicyer.test.dubbo.service.ICaculator"
ref="linkToImpl" />

</beans>(可选)也可以用
${dubbo.port}
的形式,配置一个properties文件统一管理。# dubbo param
dubbo.applicationName=dubboProviderMain
dubbo.registryProtocol=zookeeper
dubbo.registryAddress=zookeeper://192.168.2.115:2181
dubbo.port=20881(可选)如果你不想直接用main方法加载启动,也可以通过spring去加载你的配置,比如原有业务的集成
spring-context.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"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="false" default-autowire="byName"
>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/dubbo.properties</value>
</list>
</property>
<property name="fileEncoding" value="UTF8"></property>
</bean>
<import resource="classpath:/dubbo-provider.xml"/>
</beans>

5.启动
方法一:main函数public class ServiceProviderStater {
/**
* dubbo的服务启动,其实就是开始监听设置的服务接口,即dubbo.port,此接口接收的协议默认是dubbo协议
*/
public static void main(String[] args) {
try {
//也可以加载spring容器启动dubbo
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-main-provider.xml");
context.start();
} catch (Exception e) {
e.printStackTrace();
}
synchronized (ServiceProviderStater.class) {
while (true) {
try {
ServiceProviderStater.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 也可以使用Dubbo框架提供的Main方法类运行,个人觉得两种差不多
*/
}
方法二:随tomcat启动(这里是用spring来带起的,如果不想用spring,就直接读dubbo的配置文件即可)
其实就是用tomcat的启动钩子替代main的作用
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/spring-context.xml
</param-value>
</context-param>
<!--初始化spring上下文 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>启动成功的话,应该能在dubbo-admin的后台服务里看到注册的服务
坑:
(1)provider的dubbo.properties是与consumer不同的,因为不需要dubbo.port=20880这个属性(2)beans xmlns有很多失效了,请改成新的版本号尝试。
(3)如果使用tomcat启动,启动的端口号记得修改
(4)启动完毕后,如果你没有使用dubbo-admin,请用telnet尝试连接服务本身和注册中心,执行ls指令查看服务是否注册了。
附项目结构图



dubbo-main-provider.xml自己改成dubbo-provider.xml就行,我这里是为了做不同启动方式测试区分用的。

四、编写consumer
如之前所说,consumer是指调用者而非用户,所以其实你可以直接写main方法调用。
1.创建接口
直接把provider的粘过来即可,建议保持命名空间结构一致。
2.配置<?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://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不需要与提供方一样 -->
<dubbo:application name="dubboConsumer" />

<!-- 指定注册中心的ip -->
<dubbo:registry address="zookeeper://192.168.2.115:2181"/>

<!-- 引用注册中心提供的服务 ref改成reference -->
<dubbo:reference id="dontCare" interface="me.cicyer.test.dubbo.service.ICaculator" check="false" />
</beans>id随意,关键是interface,请确认interface和服务提供者一致(我不清楚继承接口是否也可以,请自行尝试),否则会出现create bean失败的情况
3.启动
直接main类,如果有随服务器启动的需求,请注意避让端口。原理还是用启动钩子来替代main函数public class ServiceConsumerTester {

public static void main(String[] args) {
try {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml");
context.start();
ICaculator linkToImpl = (ICaculator)context.getBean("dontCare");
System.out.println("sum:"+linkToImpl.sum(1,200));
} catch (Exception e) {
e.printStackTrace();
}
}
}坑
(1)任何的错误发生时,请先确认你使用的所有端口是可以访问的。必要时关闭所有防火墙,然后用telnet去一一测试
(2)无法实例化接口的实现类。
    有很多可能,先确认你的接口和provider一致,并且配置文件里可以直接链接到此接口。还不行的话就尝试更换jar包版本。
(3)提示服务未注册
    多半是端口未开放。请先去注册中心查看确认服务的状态是可用。然后是确认接口是否和提供者一致。

(4)如果以上都对了还是有问题,建议查看使用的dubbo版本是否正确,直接dubbo提到最新版,然后一层一层解决依赖问题。
附目录结构:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: