Spring Boot 1.5.8整合Dubbo

废话不多说,今天说说Spring Boot和Dubbo的整合,注册服务中心用的是Zookeeper,至于Dubbo、Zookeeper为何物我在此不再多言,不知道是什么自己去百度,本文适用于对微服务或者RPC了解的人准备的!

先介绍一下整合过程中用到的主要软件的版本:

1
2
3
4
Spring Boot: 1.5.8.RELEASE
Dubbo: dubbo-spring-boot-starter 0.1.1
Zookeeper: 3.4.10
dubbo-admin:2.5.4

其中dubbo-admin使用的是老版本的,新版本的大家可以到github上去搜索,这里给出这个版本的下载地址,我不保证任何时候都可以使用
dubbo-admin-2.5.4
Dubbo使用的是alibaba官方提供的starter :

1
2
3
4
5
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.1</version>
</dependency>

如果您的工程遇到了依赖问题, 请尝试添加如下 Maven 参考到工程的 pom.xml 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
<repositories>
<repository>
<id>sonatype-nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

从现在开始, dubbo-spring-boot-project 将在每个发布中发行两个版本 :

  • 0.2.x 是支持 Spring Boot 2.x 的主要版本(推荐,长期维护)
  • 0.1.x 是支持 Spring Boot 1.x 的维护版本(兼容,短期维护)
    1
    2
    3
    版本	Java	Spring Boot	Dubbo
    0.2.0 1.8+ 2.0.x 2.6.2+
    0.1.1 1.7+ 1.5.x 2.6.2+
    以上牵涉到需要安装的软件,需要大家自行准备,本文的重点不在于此!友情提示,使用上面版本的dubbo-admin是个war包可以之前部署在Tomcat中,注意其中配置文件中的Zookeeper的地址,请修改成自己可用的Zookeeper地址!

我之前写过一个基于Spring Boot和Spring Cloud的BT搜索项目,我主要是想用这个项目练手Spring Cloud,其中用了Zuul、Fegin、Ribbon、Spring Config、Hystrix、Eureka等组件。下面开始正式的编码,Spring Boot和Dubbo的整合。其中问题有很多,浪费了我国庆假期中的一天,其实最后发现问题解决很简单。

####由服务提供方为服务消费方暴露接口

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
44
45
46
47
48
49
50
51
52
53
package net.ydstudio.dubbo.search.api.service;

import net.ydstudio.dubbo.search.api.document.BtSearchDocument;
import net.ydstudio.dubbo.search.api.model.EsSearchHotResult;

import java.io.IOException;

/**
* Created by Sam on 18/7/7.
*/
public interface BtSearchService {

/**
* 创建索引
* @return
* @throws IOException
*/
Boolean createIndex() throws IOException;
/**
* 通过word查询 文档
* @param word
* @return
* @throws IOException
*/
BtSearchDocument findOne(String word) throws IOException;
/**
* 根据id删除文档
* @param word
* @throws IOException
* @return
*/
Boolean delete(String word) throws IOException;

/**
* 保存 document
* @param word
* @throws IOException
* @return true or false
*/
Boolean save(String word) throws IOException;
/**
* 删除索引
* @return
* @throws IOException
*/
Boolean deleteIndex() throws IOException;

/**
* 热搜词
* @return
*/
EsSearchHotResult hotWordList();
}

####服务提供方

pom.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
    <dependencies>
<dependency>
<groupId>net.ydstudio.dubbo</groupId>
<artifactId>search-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.1</version>
</dependency>

</dependencies>
</project>
实现暴露的接口
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package net.ydstudio.dubbo.search.service;

import com.alibaba.dubbo.config.annotation.Service;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.Search;
import net.ydstudio.dubbo.search.api.document.BtSearchDocument;
import net.ydstudio.dubbo.search.api.model.EsSearchHotResult;
import net.ydstudio.dubbo.search.api.service.BtSearchService;
import net.ydstudio.dubbo.search.util.Md5Util;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
* Created by Sam on 18/7/7.
*/
@Service
public class BtSearchServiceImpl implements BtSearchService,EsSearchService<BtSearchDocument> {

/**
* 索引
*/
public static final String INDEX_NAME = "search";

/**
* 索引类型
*/
public static final String TYPE = "searchWord";


@Value("classpath:mapping/searchMapping.json")
private Resource mappingFile;

@Autowired
private JestClient jestClient;

@Override
public Boolean createIndex() throws IOException {

return createESIndex(jestClient, mappingFile, INDEX_NAME, TYPE);
}

@Override
public BtSearchDocument findOne(String word) throws IOException {

String id = Md5Util.md5(word);
return findDocument(jestClient, INDEX_NAME, TYPE, id, BtSearchDocument.class);
}

@Override
public Boolean delete(String word) throws IOException {

String id = Md5Util.md5(word);
return deleteDocument(jestClient, INDEX_NAME, TYPE, id);
}

@Override
public Boolean save(String word) throws IOException {

String id = Md5Util.md5(word);
BtSearchDocument document = this.findOne(id);

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();

if (StringUtils.isEmpty(document)){
document = new BtSearchDocument();
document.setId(id);
document.setCreated(format.format(date));
document.setNum(1);
document.setWord(word);

}else {
document.setNum(document.getNum()+1);
}

document.setUpdated(format.format(date));

return saveDocument(jestClient, INDEX_NAME, TYPE, id, document);
}


@Override
public Boolean deleteIndex() throws IOException {
return deleteESIndex(jestClient, INDEX_NAME);
}

@Override
public EsSearchHotResult hotWordList() {

// match_all
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
boolQuery.must(queryBuilder);

FieldSortBuilder sortBuilder = SortBuilders.fieldSort("num");
sortBuilder.order(SortOrder.DESC);
searchSourceBuilder.query(boolQuery);

searchSourceBuilder.sort(sortBuilder);

// 构建Search对象
Search search = new Search.Builder(searchSourceBuilder.toString())
.addIndex(INDEX_NAME)
.addType(TYPE)
.build();

EsSearchHotResult esSearchHotResult = new EsSearchHotResult();
try {
JestResult result = jestClient.execute(search);
List<BtSearchDocument> list = result.getSourceAsObjectList(BtSearchDocument.class);


esSearchHotResult.setTook(result.getValue("took").toString());
esSearchHotResult.setDocumentList(list);


} catch (IOException e) {
e.printStackTrace();
}
return esSearchHotResult;
}
}

search服务提供方的application的配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dubbo:
application:
id: search-provider
name: search-provider
protocosl:
id: dubbo
name: dubbo
port: 20880
scan:
basePackages: net.ydstudio.dubbo.search.service
registry:
id: my-registry
address: zookeeper://xx.xx.xxx.xxx:xxx
parameters:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0

注意 basePackages项配置的包路径,他对应的是设置扫描路径即被注解@service和@Reference描述的接口(或者说是暴露接口的实现类的包路径,这个很重要,我在此处耽搁了很久),这个配置可以使用 @EnableDubbo 注解替代(加在启动类上)

####服务消费方
#####pom.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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<dependencies>
<dependency>
<groupId>net.ydstudio.dubbo</groupId>
<artifactId>bt-model</artifactId>
</dependency>
<dependency>
<groupId>net.ydstudio.dubbo</groupId>
<artifactId>search-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.1</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator</artifactId>
<type>pom</type>
</dependency>
</dependencies>
配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dubbo:
application:
id: bt-search
name: bt-search
protocosl:
id: dubbo
name: dubbo
port: 20880
scan:
basePackages: net.ydstudio.dubbo.bt
registry:
id: my-registry
address: zookeeper://xx.xx.xxx.xxx:xxx
parameters:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0

注意 basePackages 设置扫描路径,扫描被注解@service和@Reference的接口

RPC调用
1
2
@Reference
private BtSearchService btSearchService;

使用com.alibaba.dubbo.config.annotation.Reference中的 @Reference注解修饰接口BtSearchService ,然后像普通的bean使用即可。

整合总结

由于软件更新的快,或者软件项目的生存周期太短,软件对应的说明文档会跟不上。Dubbo现在已经捐献给了Apache,这一方面可能会好一点。大家在开发的时候注意细心一点,多去看看GitHub,不然问题会很多!

附注参考资料
【官方Dubbo和Spring Boot整合的GitHub地址】

  • 作者: Sam
  • 发布时间: 2018-10-06 23:06:57
  • 最后更新: 2019-12-09 23:03:26
  • 文章链接: https://ydstudios.gitee.io/post/53410e91.html
  • 版权声明: 本网所有文章除特别声明外, 禁止未经授权转载,违者依法追究相关法律责任!