Spring Boot集成Dubbo 并且使用使用zookeeper作为注册中心
前言
本文全程在Windos下操作,大致操作与Linux相差无异,具体细节请百度,有条件的可以谷歌!
需要了解的知识点
- Dubbo 和 zookeeper 环境以及了解这两个是个什么东东
- Spring Boot 知识点,仅限于包结构 pom依赖 继承等
- Maven 聚合工程
- JDK 和 tomcat 环境配置等
首先环境配置
JDK 8
Maven 3.x
Spring Boot 1.5.22
tomcat 8.x
Mysql 5.5
dubbo 2.5.4
zookeeper 3.5.8
关于Dubbo 、zookeeper 以及微服务是什么东西,请百度,如不知道就不要往下看了。
首选需要了解和安装Dubbo 和 zookeeper 环境 可以查看 Windows下搭建dubbo和zookeeper环境
搭建Maven聚合项目
先新建父级工程
输入项目名和groupid 和 ArtifactId
然后在父级包上右键新建Module
如下图,点击完成即可。
等等新建结束后点击父级pom
可以看到子maven模块
项目结构
新建后的pom文件
4.0.0
com.gamll
gamll-parent
1.0-SNAPSHOT
父级maven
gmall-api
gmall-common-util
service-util
gmall-user-service-dir/gmall-user-service
gmall-user-service-dir/gmall-user-web
引入Spring Boot 依赖后 和 部分依赖后,依赖维护
4.0.0
com.gamll
gamll-parent
1.0-SNAPSHOT
父级maven
gmall-api
gmall-common-util
service-util
gmall-user-service-dir/gmall-user-service
gmall-user-service-dir/gmall-user-web
org.springframework.boot
spring-boot-starter-parent
1.5.22.RELEASE
pom
UTF-8
UTF-8
1.8
1.2.46
1.0.10
2.6.0
0.10
1.3.1
1.9.20
1.4.01
1.9.1
1.11.2
4.5.5
3.7
1.2.3
2.9.0
5.3.2
4.5.1
1.9.3
com.alibaba
fastjson
${fastjson.version}
com.alibaba
dubbo
${dubbo.version}
com.101tec
zkclient
${zkclient.version}
com.gitee.reger
spring-boot-starter-dubbo
${dubbo-starter.version}
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.version}
net.sourceforge.nekohtml
nekohtml
${nekohtml.version}
xml-apis
xml-apis
${xml-apis.version}
org.apache.xmlgraphics
batik-ext
${batik-ext.version}
org.jsoup
jsoup
${jsoup.version}
org.apache.httpcomponents
httpclient
${httpclient.version}
org.apache.commons
commons-lang3
${commons-lang3.version}
tk.mybatis
mapper-spring-boot-starter
${mapper-starter.version}
redis.clients
jedis
${jedis.version}
io.searchbox
jest
${jest.version}
net.java.dev.jna
jna
${jna.version}
commons-beanutils
commons-beanutils
${beanUtils.version}
gmall-api
存放实体类,和定义service接口
gmall-common-util
存放一些通用的工具方法以及service和controller都通用的依赖
service-util
存放service需要的一些依赖 比如数据库驱动 redis等。
然后gmall-user-service-dir 文件夹存放 dubbo 服务提供者和消费者
新建如上所示
gmall-user-service 服务提供者
gmall-user-web 消费者
以上每个子模块 中继承父级的pom依赖
gamll-parent
com.gamll
1.0-SNAPSHOT
这里只贴gmall-common-util的pom文件,其他子模块结构的都一样
com.alibaba
dubbo
com.101tec
zkclient
org.slf4j
slf4j-log4j12
com.gitee.reger
spring-boot-starter-dubbo
gmall-api
gamll-parent
com.gamll
1.0-SNAPSHOT
4.0.0
gmall-api
用户实体类服务
tk.mybatis
mapper-spring-boot-starter
1.2.3
org.springframework.boot
spring-boot-starter-jdbc
gmall-user-service
4.0.0
gamll-parent
com.gamll
1.0-SNAPSHOT
com.gmall
gmall-user-service
0.0.1-SNAPSHOT
gmall-user-service
用户服务生产者 , 也就是dubbo 提供端
1.8
com.gamll
gmall-api
1.0-SNAPSHOT
com.gamll
service-util
1.0-SNAPSHOT
com.gmalluser
gmall_user
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-maven-plugin
gmall-user-web
gamll-parent
com.gamll
1.0-SNAPSHOT
4.0.0
com.gmall
gmall-user-web
0.0.1-SNAPSHOT
gmall-user-web
用户服务消费者 也就是dubbo 消费端 对外的接口
1.8
com.gamll
gmall-api
1.0-SNAPSHOT
com.gamll
service-util
1.0-SNAPSHOT
com.h2database
h2
runtime
org.springframework.boot
spring-boot-maven-plugin
service-util
gamll-parent
com.gamll
1.0-SNAPSHOT
4.0.0
service-util
com.gamll
gmall-common-util
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-jdbc
org.mybatis.spring.boot
mybatis-spring-boot-starter
mysql
mysql-connector-java
runtime
redis.clients
jedis
搭建dobbo提供者和消费者
maven子模块服务提供者gmall-user-service
和消费者 gmall-user-web
服务提供者
这里面新建 数据库访问 和 和 service实现类 同时在yml里配置将服务注册到 中
UmsMemberMapper
这里面提供dao查询接口 继承通用mapper接口
实体类依赖在gmall-api
模块中
Mapper依赖在service-util
模块中
@Mapper
public interface UmsMemberMapper extends tk.mybatis.mapper.common.Mapper {
/**
* 查询所有
* @return
*/
List selectAllUmsMebers();
}
UmsMemberMapper.xml
id, member_level_id, username, password, nickname, phone, status, create_time, icon,
gender, birthday, city, job, personalized_signature, source_type, integration, growth,
luckey_count, history_integration
ums_member sql语句
CREATE TABLE `ums_member` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`member_level_id` bigint(20) DEFAULT NULL,
`username` varchar(64) DEFAULT NULL COMMENT '用户名',
`password` varchar(64) DEFAULT NULL COMMENT '密码',
`nickname` varchar(64) DEFAULT NULL COMMENT '昵称',
`phone` varchar(64) DEFAULT NULL COMMENT '手机号码',
`status` int(1) DEFAULT NULL COMMENT '帐号启用状态:0->禁用;1->启用',
`create_time` datetime DEFAULT NULL COMMENT '注册时间',
`icon` varchar(500) DEFAULT NULL COMMENT '头像',
`gender` int(1) DEFAULT NULL COMMENT '性别:0->未知;1->男;2->女',
`birthday` date DEFAULT NULL COMMENT '生日',
`city` varchar(64) DEFAULT NULL COMMENT '所做城市',
`job` varchar(100) DEFAULT NULL COMMENT '职业',
`personalized_signature` varchar(200) DEFAULT NULL COMMENT '个性签名',
`source_type` int(1) DEFAULT NULL COMMENT '用户来源',
`integration` int(11) DEFAULT NULL COMMENT '积分',
`growth` int(11) DEFAULT NULL COMMENT '成长值',
`luckey_count` int(11) DEFAULT NULL COMMENT '剩余抽奖次数',
`history_integration` int(11) DEFAULT NULL COMMENT '历史积分数量',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_phone` (`phone`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='会员表';
服务提供者类
UmsMemberServiceImpl
需要注意的是以前我们在单体服务中 service实现类采用Spring 提供的@service
注解将bean注入到IOC容器中
但现在我们是用dubbo实现微服务,需要使用dubbo的@service
注解将该服务注册到zookeeper中,让消费者从容器中获取进行消费。
顾名思义就是提供服务供别人调用的,相当于spring中的Service的实现类。 使用也很简单,就是一个注解加一份配置 提供端在实现类上增加注解 @Service,和spring的是一样的但是引的包是不一样的。
package com.gmall.gmall.user.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.gamll.api.bean.UmsMember;
import com.gamll.api.service.UmsMemberService;
import com.gmall.gmall.user.service.dao.UmsMemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service //这里@Service 注解需要使用dubbo 的注解
public class UmsMemberServiceImpl implements UmsMemberService {
@Autowired
private UmsMemberMapper umsMemberMapper;
@Override
public List getUmsMemberList() {
return umsMemberMapper.selectAllUmsMebers();
}
@Override
public UmsMember findUmsMemberById(long id) {
return umsMemberMapper.selectByPrimaryKey(id);
}
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class})
public int addUmsMember(UmsMember umb) {
return umsMemberMapper.insert(umb);
}
@Override
@Transactional(rollbackFor = {Exception.class,RuntimeException.class})
public int updateUmsMember(UmsMember umb) {
return umsMemberMapper.updateByPrimaryKey(umb);
}
}
main方法
需要开启Mapper扫描 这里使用了通用Mapper 必须用到通用mapper的@MapperScan
注解扫描mapper
以及开启事务
@SpringBootApplication
@tk.mybatis.spring.annotation.MapperScan("com.gmall.gmall.user.service.dao")
@EnableTransactionManagement
public class GmallUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GmallUserServiceApplication.class, args);
}
}
最后yml中配置注册中心以及dubbo中的服务信息以及mybatis的配置
server:
port: 10002
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/gmall0105?useunicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
dubbo:
# dubbo中的服务名称
application:
name: user-service-server
protocol:
# dubbo中的通信协议名称
name: dubbo
registry:
# zookeeper注册中心的地址加端口号
address: 127.0.0.1:2181
# zookeeper注册中心协议
protocol: zookeeper
# dubbo的服务扫描路径
base-package: com.gmall
#mybatis 映射 xml和pojo映射
mybatis:
type-aliases-package: com.gmalluser.pojo
mapper-locations: classpath:mapper/*.xml
logging:
level: debug
最后启动一下Spring Boot
别忘了启动dubbo和zookeeper
可以看到已经将服务注册到zookeeper中了
打开dubbo服务监控页面
可以看到服务提供者
服务消费者
上面已经将服务注册到zookeeper中了,这里我们将服务拿出来进行消费
首先配置Yml
配置注册地址端口等协议
server:
port: 10003
spring:
dubbo:
# dubbo中的服务名称
application:
name: user-web
protocol:
# dubbo中的通信协议名称
name: dubbo
registry:
# zookeeper注册中心的地址加端口号
address: 127.0.0.1:2181
# zookeeper注册中心协议
protocol: zookeeper
# dubbo的服务扫描路径
base-package: com.gmall
consumer:
# 访问提供端服务的超时时间,默认是1000毫秒
timeout: 30000
# 是启动消费端时,是否检查服务端能否正常访问。如果选择true,那启动消费端时,必须保证提供端服务正常,否则接口无法注入
check: false
UmsMemberController
新建controller 消费服务查询数据
以前在单体中我们是从IOC容器中将bean拿出来然后调用方法进行查询,但在dubbo分布式项目中是用dubbo 的service 也就是用@Reference
将服务从zookeeper拿出来,注入到controller中 然后调用指定方法进行查询
@RequestMapping("/api/umb")
@RestController
public class UmsMemberController {
//dubbo 的service
@Reference
private UmsMemberService umsMemberService;
@RequestMapping("/findAll")
public List all() {
return umsMemberService.getUmsMemberList();
}
@RequestMapping("/findById")
public UmsMember all(long id) {
return umsMemberService.findUmsMemberById(id);
}
}
然后启动消费者
如果启动报错
java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at com.alibaba.dubbo.config.AbstractConfig.toString(AbstractConfig.java:474) ~[dubbo-2.6.2.jar:2.6.2]
at java.lang.String.valueOf(String.java:2994) [na:1.8.0_181]
at java.lang.StringBuilder.append(StringBuilder.java:131) [na:1.8.0_181]
at com.alibaba.dubbo.config.spring.beans.factory.annotation.AbstractAnnotationConfigBeanBuilder.build(AbstractAnnotationConfigBeanBuilder.java:79) [dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.buildReferenceBean(ReferenceAnnotationBeanPostProcessor.java:385) [dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.access$100(ReferenceAnnotationBeanPostProcessor.java:65) [dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement.inject(ReferenceAnnotationBeanPostProcessor.java:363) [dubbo-2.6.2.jar:2.6.2]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at com.alibaba.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.postProcessPropertyValues(ReferenceAnnotationBeanPostProcessor.java:92) [dubbo-2.6.2.jar:2.6.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1400) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1395) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) [spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE]
at com.springboot.dubbo.DubboApplication.main(DubboApplication.java:12) ~[classes/:na]
Caused by: java.lang.IllegalStateException: Failed to check the status of the service com.spring.boot.service.UserService. No provider available for the service com.spring.boot.service.UserService from the url zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=spring-boot-dubbo-consumer&dubbo=2.6.2&interface=com.spring.boot.service.UserService&methods=getUser&pid=40168®ister.ip=192.168.1.5&side=consumer×tamp=1553586960033 to the consumer 192.168.1.5 use dubbo version 2.6.2
at com.alibaba.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:422) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:333) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:163) ~[dubbo-2.6.2.jar:2.6.2]
at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:66) ~[dubbo-2.6.2.jar:2.6.2]
... 43 common frames omitted
是因为 main方法上服务提供者的主类上没有配置注解
@SpringBootApplication
@EnableDubbo
public class GmallUserWebApplication {
public static void main(String[] args) {
SpringApplication.run(GmallUserWebApplication.class, args);
}
}
然后启动即可
可以发现成功注册
调用查询接口测试
发现成功查询出数据
分布式就可以基于这种方式实现不同模块间的调用。每一个实现服务的消费端和提供端分离。
dubbo和zookeeper分布式架构
执行流程:
- Provider:服务的提供者,负责对外提供服务,提供者在启动的时候,需要向Registry注册自己能够提供
的服务 - Consumer:服务的消费者,消费者在启动的时候,需要向Registry订阅自己需要的服务
- Registry:注册中心,授受注册和订阅,会异步的通知订阅者,向消费者提供服务列表
当消费者需要执行远程过程调用时,会从Registry获取到服务地址列表(基于负载均衡算法)进行调用,
如果调用失败会重新选择新的提供者再次调用 - Monitor:监控中心,统计服务的调用次数和调用时间,服务消费者和提供者会在内存中累计调用次数和
调用时间,定时每分钟向监控中心发送一次统计数据
代码地址 分支 gmall0105