Dubbo是阿里開源的一個微服務框架,性能很高,現在由Apache維護。
此處寫一個demo,訂單服務獲取訂單所屬用戶的信息,order-service調用user-service。
1、新建子模塊api,groupId為com.chy.mall,artifactId為api
這個模塊用來存放微服務中所有的實體類,以及所有的服務提供者提供的服務接口。
只寫實體類和接口,使用普通的maven項目即可。
(1)pom.xml
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency>
我要使用lombok,添加lombok的依賴
(2)新建包model,用於存放所有的model。包下新建實體類User:
//注意:實體類要可序列化 @Getter @Setter public class User implements Serializable { private Integer id; private String username; private String password; private String tel; private String address; }
(3)新建包service,用於存放所有服務提供者提供的服務接口。包下新建UserService:
public interface UserService { User findUserById(Integer id); }
建包的方式有很多,比如用戶服務要提供很多接口,可以在service下新建包user-service;
比如一個服務提供者一個包,user-service包下新建model包、service包,分別放本服務的model、提供的服務接口。
之所以把model寫在這個子模塊中,是因為服務接口的參數類型、返回值類型很多都要聲明為實體類。
(4)使用maven install打包為jar安裝到本地倉庫,實際開發是安裝到公司私服。
如果后續要更新、維護這個jar包,實際開發是以新版本號的方式來開發、安裝,要使用新的jar包需要改pom.xml中的版本號;
自己操作的話,可以直接在原來代碼的基礎上改(使用原版本號),然后安裝覆蓋掉倉庫中原來安裝的jar包。
2、新建子模塊user-service,springboot項目,作為服務提供者。groupId為com.chy.mall,artifactId為user-service
(1)pom.xml
<!-- api接口的jar包 --> <dependency> <groupId>com.chy.mall</groupId> <artifactId>api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- dubbo的依賴 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.6</version> </dependency> <!-- zk的依賴 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>2.7.6</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
使用zk作為注冊中心、配置管理中心,這里添加的zk依賴是作為zkCli。
zk的依賴要用<exclusions>去掉slf4j部分,因為spring-boot-strat已經包含了slf4j,如果不去掉會報錯:slf4j綁定了多個jar包中的Logger......
像這種多處引入同一個依賴的,用maven看一下依賴關系圖,重復的保留一個即可。
dubbo可以使用多種注冊中心,比如zk、redis等,上面的zk依賴只包含以zk作為注冊中心的依賴,服務只能以zk作為注冊中心。
zk的依賴可以換為以下2種中的任一種,均包含了dubbo支持的所有的注冊中心的依賴:
<dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>2.7.6</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.8</version> </dependency>
(2)新建包service,包下新建類UserServiceImpl實現服務接口UserService
//此處的@Service是dubbo下的注解,不是spring的注解 @Service public class UserServiceImpl implements UserService { @Override public User findUserById(Integer id) { User user = new User(); user.setId(id); user.setUsername("chy"); return user; } }
實現服務接口的類都放到一個包下。
(3)配置文件
spring.application.name=user-service
#如果指定了spring應用名稱,可以缺省dubbo的應用名稱,這2個至少要配置1個。缺省dubbo的應用名稱時默認值是spring的應用名稱
#dubbo.application.name=user-service
#注冊中心地址
dubbo.registry.address=zookeeper://192.168.1.9:2181
#端口號可以寫在address中,也可以單獨寫。實質是從address中獲取的port是null,后面設置的port覆蓋了null
#dubbo.registry.port=2181
#指定dubbo使用的協議、端口
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
#指定注冊到zk上超時時間,ms
dubbo.registry.timeout=10000
#指定實現服務(提供服務)的包
dubbo.scan.base-packages=com.chy.user-service.service
連接到zkServer的時間開銷大,如果不將注冊的超時時間設置大一些,可能會報錯:zookeeper not connected,時間不夠,還沒連上就超時取消了。
提供服務的包也可以引導類上指定:
@SpringBootApplication // @EnableDubbo //會掃描所有的包,從中找出dubbo的@Service標注的類 // @DubboComponentScan(basePackages = "com.chy.user-service.service") //只掃描指定的包 public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }
可以在配置文件中配置,也可以使用上面2個注解中的一個。
3、新建子模塊order-service,springboot web項目,作為服務消費者。groupId為com.chy.mall,artifactId為order-service
(1)pom.xml
<!-- api接口的jar包 --> <dependency> <groupId>com.chy.mall</groupId> <artifactId>api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- dubbo的依賴 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.6</version> </dependency> <!-- zk的依賴 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>2.7.6</version> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency>
web項目自然要有spring-boot-start-web。
(2)新建包controller,包下新建類OrderController來調用服務
@Controller public class OrderController { @Reference //注入要調用的服務 private UserService userService; @RequestMapping("/user/{id}") @ResponseBody public User getUser(@PathVariable Integer id){ //調用服務 User user= userService.findUserById(id); return user; } }
一般是在service層調用服務,此處只是demo
(3)配置文件
#應用名稱 spring.application.name=order-service #dubbo.application.name=order-service
#注冊中心地址 dubbo.registry.address=zookeeper://192.168.1.9:2181 #dubbo.registry.port=2181
#協議、端口 dubbo.protocol.name=dubbo dubbo.protocol.port=20880
#連接zk的超時時間,ms dubbo.registry.timeout=10000
#啟動應用時是否檢查注冊中心上有沒有依賴的服務,默認true #dubbo.consumer.check=false
缺省dubbo.consumer.check配置時,默認為true,要檢查。
消費者連接注冊中心時,會訂閱要調用的服務,如果提供該服務的服務器一台都沒有,會報錯,這個消費者無法啟動,這樣在消費者啟動時就能檢查到是否有可用的生產者,提前發現問題。
調試時,如果先啟動消費者,后啟動|未啟動生產者,消費者往往啟動不了,報錯:創建不了xxx bean,因為 Injection of @Reference dependencies is failed ,沒有生產者提供該服務。
設置為false,消費者啟動時不檢查,就算沒有生產者提供該服務,消費者也能正常啟動,只是調用該服務時會出錯。
4、先啟動生產者,再啟動消費者
地址欄輸入 http://127.0.0.1:8080/user/1 看到已經輸出user對象信息
zkServer上,dubbo的根目錄是/dubbo,
一個提供的服務對應一個znode,包名.服務接口名 的形式,/dubbo/service.UserService
這個節點的子節點providers存儲此服務的所有提供者的注冊信息,子節點consumers存儲訂閱此服務的所有消費者的信息。
dubbo @Service標注的類所實現的接口,會自動在zkServer上創建一個對應的znode,包名.接口名的形式;
生產者實現該接口,並使用dubbo @Service標識該類是服務提供者,實現的接口就是它提供的服務;消費者使用@Reference來訂閱、引用服務。
說明
官方demo是用spring整合dubbo、使用xml文件進行配置,因為springboot是近幾年才推出、流行的,對dubbo的支持比spring要差一些,少數(冷門)配置尚未實現。
dubbo的配置可以寫在springboot配置文件中,也可以在resources下新建spring配置文件,來寫dubbo的配置。
Dubbo的架構:
http://dubbo.apache.org/zh-cn/docs/user/preface/architecture.html
dubbo配置加載流程:
http://dubbo.apache.org/zh-cn/docs/user/configuration/configuration-load-process.html
dubbo的協議有很多種,最常用的是dubbo協議:
http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html
集群容錯:
http://dubbo.apache.org/zh-cn/docs/user/demos/fault-tolerent-strategy.html
調用服務時,如果調用失敗,默認會重試2次,總共3次。
dubbo的注冊中心也有很多種,設置可以不要注冊中心,消費者可以通過ip、port直連提供者,直接調用。
一般使用zk作為注冊中心。
dubbo一般使用20880端口,可以改,
消費者、提供者使用的端口可以相同,也可以不同。
指定注冊中心:
#協議、ip:port可以寫在一起
dubbo.config-center.address=zookeeper://192.168.1.9:2181
#也可以分開寫
dubbo.registry.protocol=zookeeper
dubbo.registry.address=192.168.1.9:2181
#如果是集群,逗號分隔
dubbo.registry.address=192.168.1.9:2181,192.168.1.10:2181
設置連接到注冊中心的超時時間:
#這個是提供者、消費者都可以使用的
dubbo.registry.timeout=10000
#也可以使用專門的
dubbo.consumer.timeout=10000
dubbo.provider.timeout=10000
升級系統時dubbo的服務接口不兼容怎么辦?
使用版本號,dubbo的@Service、@Reference都可以指定version屬性,@Service指定提供的是該服務接口哪個版本的實現,@Reference指定調用該服務接口的哪個版本,提供者、消費者使用版本號來對接。
xml配置思想相同。