基于Dubbo的Hessian协议实现远程调用

前言

创建两个项目,一个provider提供dubbo服务,一个client消费服务。
源码地址:https://gitee.com/qianxunclub/java-demo/tree/master/chapter-2
目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ tree -I target

chapter-2
├── api
│   ├── pom.xml
│   └── src
│   └── main
│   └── java
│   └── com
│   └── qianxunclub
│   └── chapter2
│   └── api
│   └── DemoService.java
├── client
│   ├── pom.xml
│   └── src
│   └── main
│   ├── java
│   │   └── com
│   │   └── qianxunclub
│   │   └── chapter2
│   │   └── client
│   │   └── ClientMain.java
│   └── resource
│   ├── demo-consumer.xml
│   └── log4j.properties
├── pom.xml
└── provider
├── pom.xml
└── src
└── main
├── java
│   └── com
│   └── qianxunclub
│   └── chapter2
│   └── provider
│   ├── DemoServiceImpl.java
│   └── ProviderMain.java
└── resource
├── META-INF
│   └── spring
│   └── demo-provider.xml
└── log4j.properties

1、在provider的pom.xml中引入maven包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<dependency>
<groupId>com.qianxunclub</groupId>
<artifactId>chapter-2-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.26</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>

2、在provider中添加配置文件

在provider的resource/META-INF/spring下建个xml, 例如:demo-provider.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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"
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://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<context:annotation-config/>
<context:component-scan base-package="com.qianxunclub.chapter2.provider"/>
<!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
<dubbo:application name="demo-provider" owner="lily"/>

<!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
<dubbo:registry protocol="zookeeper" address="qianxunclub.com:2181"/>

<!--当前服务发布所依赖的协议;WebService、Thrift、Hessian、http-->
<dubbo:protocol name="dubbo" port="20880"/>

<!--增加hessian协议-->
<dubbo:protocol name="hessian" port="8090" server="jetty" />

</beans>

ps:该xml文件默认需要建在resource/META-INF/spring文件夹下。多说无益,上dubbo源码。
从ProviderMain.java中

1
Main.main(args);

点进去main方法,查看main方法中Container接口的其中之一的实现类SpringContainer中可以看到默认路径:

1
public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";

也可以自定义路径:

1
2
3
4
5
6
7
8
public void start() {
String configPath = ConfigUtils.getProperty("dubbo.spring.config");
if(configPath == null || configPath.length() == 0) {
configPath = "classpath*:META-INF/spring/*.xml";
}
context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
context.start();
}

点进去getProperty方法,一路ctrl下去,可以看到ConfigUtils.java中自定义路径的规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Properties getProperties() {
if(PROPERTIES == null) {
Class var0 = ConfigUtils.class;
synchronized(ConfigUtils.class) {
if(PROPERTIES == null) {
String path = System.getProperty("dubbo.properties.file");
if(path == null || path.length() == 0) {
path = System.getenv("dubbo.properties.file");
if(path == null || path.length() == 0) {
path = "dubbo.properties";
}
}
PROPERTIES = loadProperties(path, false, true);
}
}
}
return PROPERTIES;
}

在resource下创建dubbo.properties文件,内容如下:

1
2
#dubbo配置的自定义路径
dubbo.spring.config=classpath*:hello/*.xml

3、在api模块中添加对外抛出的接口

1
2
3
public interface DemoService {
String sayHello(String name);
}

并在provider中添加该接口的实现类:

1
2
3
4
5
6
7
8
9
10
import com.qianxunclub.chapter2.api.DemoService;
import org.springframework.stereotype.Service;

@Service("demoService")
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "hello:"+name;
}
}

demo-provider.xml中,添加 对外抛出接口:

1
2
3
4
    <!--服务发布的配置,需要暴露的服务接口-->
<dubbo:service
interface="com.qianxunclub.chapter2.api.DemoService"
ref="demoService" protocol="hessian"/>

4、调用provider中的main方法

1
2
3
4
5
6
7
8
9
10
import com.alibaba.dubbo.container.Main;
public class ProviderMain {
public static void main(String[] args) {
try {
Main.main(args);
} catch (Exception e){
System.out.println(e);
}
}
}

在provider控制台,会打印:

1
[DUBBO] Register: hessian://192.168.103.163:8090/com.qianxunclub.chapter2.provider.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.3&interface=com.qianxunclub.chapter2.provider.DemoService&methods=sayHello&owner=lily&pid=6656&server=jetty&side=provider&timestamp=1527126914293, dubbo version: 2.5.3, current host: 127.0.0.1

进入zookeeper客户端,查看服务:

5、在client的pom.xml中引入maven包

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>com.qianxunclub</groupId>
<artifactId>chapter-2-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
</dependency>

6、在client中添加配置文件

在provider的resource/META-INF下建个xml, 例如:demo-consumer.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

<!--当前项目在整个分布式架构里面的唯一名称,计算依赖关系的标签-->
<dubbo:application name="demo-client" owner="mic"/>

<!--dubbo这个服务所要暴露的服务地址所对应的注册中心-->
<dubbo:registry protocol="zookeeper" address="qianxunclub.com:2181"/>

<!--当前服务发布所依赖的协议;webserovice、Thrift、Hessain、http-->
<dubbo:protocol name="dubbo" port="20881"/>

<!--服务发布的配置,需要暴露的服务接口-->
<dubbo:reference
interface="com.qianxunclub.chapter2.api.DemoService"
id="demoService"/>

</beans>

7、调用client中的main方法

1
2
3
4
5
6
7
8
9
10
import com.qianxunclub.chapter2.api.DemoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ClientMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo-consumer.xml");
DemoService demoService = context.getBean(DemoService.class);
String r = demoService.sayHello("zhangsan");
System.out.println(r);
}
}

报错:

1
Unsupported protocol hessian in notified url: hessian://192.168.103.163:8090/com.qianxunclub.chapter2.api.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.3&interface=com.qianxunclub.chapter2.api.DemoService&methods=sayHello&owner=lily&pid=11648&server=jetty&side=provider&timestamp=1527152915485 from registry qianxunclub.com:2181 to consumer 192.168.103.163, supported protocol: [dubbo, injvm, mock, redis, registry, rmi, thrift]


原来是client端少引了个hessian依赖,加上:

1
2
3
4
5
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>

再次启动,会看到控制台打印了:hello:zhangsan。
大功告成!

本文由 lilyssh创作。可自由转载、引用,但需署名作者且注明文章出处。


当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器