導讀
Apache Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力;面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動注冊和發現。
dubbo官網:點我直達
第一個Dubbo程序(小試牛刀)
創建業務接口工程
項目結構
創建包和接口類
安裝項目
創建提供者Provider工程
項目結構
pom.xml
<?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>org.cyb</groupId> <artifactId>02-first-provider</artifactId> <version>1.0-SNAPSHOT</version> <!--編譯器依賴--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>13</maven.compiler.source> <maven.compiler.target>13</maven.compiler.target> <!--自定義版本號--> <spring-version>4.3.16.RELEASE</spring-version> </properties> <dependencies> <!--自定義工程依賴--> <dependency> <groupId>org.cyb</groupId> <artifactId>01-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--dubbo依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.7</version> </dependency> <!--netty--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency> <!--spring依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring-version}</version> </dependency> </dependencies> </project>
注意
spring-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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--當前工程名稱,該名稱將在監控平台使用--> <dubbo:application name="02-first-provider"/> <!--注冊Service,將來服務的提供者--> <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean> <!--暴露服務,采用直連的方式--> <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service> </beans>
SomeServiceImpl.java
package com.cyb.service; public class SomeServiceImpl implements SomeService{ @Override public String hello(String name) { System.out.println("Dubbo World Welcome You"+name); return "chenyanbin"; } }
RunProvider.java
package com.cyb.run; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class RunProvider { public static void main(String[] args) throws IOException { //創建spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("spring-dubbo-provider.xml"); //啟動spring容器 ((ClassPathXmlApplicationContext) ac).start(); //將當前主線程阻塞 System.in.read(); } }
創建消費者Consumer工程
項目結構圖
pom.xml
<?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>org.cyb</groupId> <artifactId>02-first-consumer</artifactId> <version>1.0-SNAPSHOT</version> <!--編譯器依賴--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>13</maven.compiler.source> <maven.compiler.target>13</maven.compiler.target> <!--自定義版本號--> <spring-version>4.3.16.RELEASE</spring-version> </properties> <dependencies> <!--自定義工程依賴--> <dependency> <groupId>org.cyb</groupId> <artifactId>01-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--dubbo依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.7</version> </dependency> <!--netty--> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.32.Final</version> </dependency> <!--spring依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring-version}</version> </dependency> </dependencies> </project>
spring-dubbo-consumer.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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--當前工程的名稱,監控中心使用--> <dubbo:application name="02-first-consumer"/> <!--消費引用--> <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> </beans>
注:端口號20880固定
RunConsumer.java
package com.cyb.run; import com.cyb.service.SomeService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class RunConsumer { public static void main(String[] args) { //創建Spring容器 ApplicationContext ac=new ClassPathXmlApplicationContext("spring-dubbo-consumer.xml"); SomeService service = (SomeService) ac.getBean("someSerivce"); service.hello("tom"); } }
運行
Zookeeper注冊中心&Zookeeper集群(Dubbo官網推薦)
拷貝生產者和消費者工程
注冊中心其他方式
地址:http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html
Zookeeper工程搭建
配置參考地址:點我直達
啟動zookeeper服務
修改提供者工程
pom.xml添加curator客戶端依賴
<!-- zk客戶端依賴:curator-framework--> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.1</version> </dependency>
注意事項
修改spring-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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--當前工程名稱,該名稱將在監控平台使用--> <dubbo:application name="03-provider-zk"/> <!--注冊Service,將來服務的提供者--> <bean id="someService" class="com.cyb.service.SomeServiceImpl"></bean> <!-- 聲明zk服務中心 --> <!-- 單機版 --> <!-- 方式一 --> <dubbo:registry address="zookeeper://192.168.1.111:2181"/> <!-- 方式二 --> <!-- <dubbo:registry protocol="zookeeper" address=""/> --> <!-- 集群配置 --> <!-- 方式一 --> <!-- <dubbo:registry address="zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181" /> --> <!-- 方式二 --> <!-- <dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" /> --> <!-- 同一Zookeeper,分成多組注冊中心 --> <!-- <dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" /> <dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" /> --> <!-- 暴露服務,將服務暴露給zk服務中心 --> <!-- <dubbo:service interface="com.cyb.service.SomeService" ref="someService" registry="N/A"></dubbo:service> --> <dubbo:service interface="com.cyb.service.SomeService" ref="someService"></dubbo:service> </beans>
修改消費者工程
pom.xml添加curator客戶端依賴
<!-- zk客戶端依賴:curator-framework--> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.0.1</version> </dependency>
修改spring-dubbo-consumer.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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--當前工程的名稱,監控中心使用--> <dubbo:application name="03-consumer-zk"/> <!-- 聲明zk服務中心 --> <!-- 單機版 --> <dubbo:registry address="zookeeper://192.168.1.111:2181"/> <!--消費引用--> <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> --> <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference> </beans>
運行
Dubbo聲明式緩存
為了進一步提高消費者對用戶的響應速度,減少提供者的壓力。Dubbo提供了基於結果的聲明式緩存。該緩存是基於消費者端的,所以使用很簡單,只需修改消費者配置文件,與提供者無關。
修改消費者配置文件
僅需在<dubbo:reference />中添加cache="true"即可
修改RunConsumer.java
緩存VS無緩存
先不加緩存,發現提供者執行2次,加上緩存提供者只執行一次
dubbo提供了三種結果緩存機制
- lru:服務級別緩存的默認機制。該機制默認可以緩存1000個結果。若超出1000,將采用最近最少使用原則來刪除緩存,以保證最熱的數據被緩存。
- threadlocal:當前線程緩存。當多個線程要對當前線程進行某一操作時首先需要查詢當前線程的某個信息,通過線程緩存,則可有效減少查詢。
- jcache:可以橋接各種緩存實現,即第三方緩存產品。
spring-dubbo-consumer.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.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!--當前工程的名稱,監控中心使用--> <dubbo:application name="03-consumer-zk"/> <!-- 聲明zk服務中心 --> <!-- 單機版 --> <dubbo:registry address="zookeeper://192.168.1.111:2181"/> <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" url="dubbo://localhost:20880"></dubbo:reference> --> <!-- <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService"></dubbo:reference> --> <!--消費引用:基於服務級別的聲明式緩存(結果緩存)--> <!--<dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" cache="true"></dubbo:reference>--> <!--消費引用:基於方法級別的聲明式緩存(結果緩存)--> <dubbo:reference id="someSerivce" interface="com.cyb.service.SomeService" > <!--lru--> <dubbo:method name="hello" cache="lru"></dubbo:method> <!--threadlocal--> <dubbo:method name="hello" cache="threadlocal"></dubbo:method> </dubbo:reference> </beans>
結果緩存的應用場景
Dubbo的結果緩存可以應用在查詢結果不變的場景。即不能使用在如下場景:消費者A調用的業務方法后從DB查詢到一個結果a,此后,消費者B對DB中的該結果相關數據進行了修改,已使該查詢結果變為b,但由於使用了結果緩存,消費者A中調用業務方法后的查詢結果將長時間為a,直到該結果由於緩存空間滿而被消除,否則,永遠無法得到更新過的結果b。
多版本控制
Dubbo的多版本控制指的是,服務名稱(接口名)相同的情況下提供不同的服務(實現類不同) ,然而消費者是通過服務名稱(接口名)進行服務查詢並進行消費的。提供者所提供的服務名稱相同,如何讓消費者通過名稱進行服務查找呢?為服務添加一個版本號,使用“服務名稱”+“版本號”的方式來唯一確定一個服務。
多版本控制主要的應用場景是:當一個接口的實現類需要升級時,可以使用版本號進行過渡(根據開閉原則,不能直接修改原實現類,只能添加新的實現類)。需要注意的是,版本號不同的服務間是不能互相引用的,因為新版本存在的目的是替換老版本。在生產環境中若存在多個提供者需要升級,一般不會一次性全部進行升級,而是會在低壓力時間段先升級一部分,然后在下次再進行部分升級,直到全部升級完成。那么,這期間就需要使用版本號進行過渡。
項目准備
拷貝項目
提供者(04-provider-version)
修改配置文件
消費者(04-consumer-version)
執行
服務分組
服務分組與多版本控制的使用方式幾乎是相同的,只要將version替換為group即可。但使用目的不同。使用版本控制的目的是為了升級,將原有老版本替換掉,將來不再提供老版本的服務,所以不同版本間不能出現相互調用。而分組的目的則不同,其也是針對相同接口,給出了多種實現類,但不同的是,這些不同實現並沒有替換掉誰的意思,是針對不同需求,或針對不同功能模塊鎖給出的實現。這些實現所提供的服務是並存的,所以他們間可以出現相互調用關系。例如,支付服務的實現,可以有微信支付實現與支付寶實現等。
服務暴露延遲
如果我們的服務啟動過程中需要warmup事件(預熱事件,與JVM重啟后的預熱過程相似,在啟動后一小段事件后性能才能達到最佳狀態)。比如初始化緩存,等待相關資源就位等。可以使用deplay進行延遲暴露。
值需要在服務提供者的<dubbo:service/>標簽中添加delay屬性,其值若為整數,則單位為毫秒,表示在指定事件后再發布服務;若為-1,則表示在spring初始化完畢后再暴露服務。
多注冊中心
很多時候一個項目中會有多個注冊中心。
同一個服務注冊到多個中心
同一個服務可以注冊到不同地域的多個注冊中心,以便為不同地域的服務消費者提供更為快捷的服務。
修改服務提供者配置文件。多個注冊中心之間使用逗號分隔。
注:不是集群!!!
不同服務注冊到不同中心
修改服務提供者配置文件
同一個服務引用自不同的中心
同一個消費者需要調用兩個不同中心服務,而調用的該服務的名稱(接口)、版本等都是相同的。不同中心的這個相同名稱的服務調用時不同數據庫中的數據,即相同服務最終執行的結果是不同的。
修改服務消費者配置文件
多協議支持
服務暴露協議
前面的示例中,服務提供者與服務消費者都是通過zookeeper連接協議連接上ZooKeeper注冊中心的。
提供者與消費者均連接上了注冊中心,那么消費者就理所當然的可以享受提供者提供的服務了么?
實際情況並不是這樣的。前述ZooKeeper協議,是消費者/提供者連接注冊中心的連接協議,而非消費者與提供者間的連接協議。
當消費者連接上注冊中心后,在消費服務之前,首先需要連接上這個服務提供者。雖然消費者通過注冊中心可以獲取到服務提供者,但提供者對於消費者來說卻是透明的,消費者並不知道真正的服務提供者是誰。不過,無論提供者是誰,消費者都必須連接上提供者才可以獲取到真正的服務,而這個連接也是需要專門的連接協議的。這個協議稱為服務暴露協議。
可是我們之前的代碼示例中並沒有看到服務暴露協議的相關配置,但仍可正常運行項目,這是為什么呢?因為采用了默認的暴露協議:Dubbo服務暴露協議。處理Dubbo服務暴露協議外,Dubbo框架還支持另外七種服務暴露協議:Hessian協議、HTTP協議、RMI協議、WebService協議、Thrift協議、Memcached協議、Redis協議;但在實際生產中,使用最多的就是Dubbo服務暴露協議。
Dubbo服務暴露協議,適合於小數據量大並發的服務調用,以及服務消費者主機數遠大於服務提供者主機數的情況。
服務暴露協議用法
在服務提供者的spring配置文件中首先需要注冊暴露協議,然后在暴露服務時具體制定所使用的已注冊的暴露協議。
注:protocol屬性用於指定當前服務所使用的暴露協議
同一服務支持多種協議
直接修改服務提供者的配置文件
不同服務使用不同協議
直接修改服務提供者配置文件
Dubbo的高級設置及使用建議
在提供者上盡量多配置消費者端屬性
提供者上盡量多配置消費者端的屬性,讓提供者實現着一開始就思考提供者服務特點、服務質量等問題。因為作服務的提供者,比服務使用方更清楚服務性能參數,如調用的超時時間、合理的重試次數等。在提供者端配置后,消費者不配置則會使用提供者端的配置值,即提供者配置可以作為消費者的缺省值。否則,消費者會使用消費者端的全局設置,這對提供者是不可控的,並且往往不合理的。
以下屬性在<dubbo:method/>上則是針對指定方法,配置在<dubbo:service/>上則是針對整個服務。
- timeout:遠程服務調用超時時限。
- retries:失敗重試次數,默認值是2。
- loadbalance:負載均衡算法,默認是隨機的random。還可以有輪詢roundrobin、最不活躍優先leastactive等。
- actives:消費者最大並發調用限制,即當Consumer對一個服務的並發調用到上限后,新調用會阻塞直到超時。
提供者上配置合理的提供者端屬性
- threads:用於指定服務線程池大小
- executes:一個服務提供者並行執行請求上限,即當提供者對一個服務的並發調用達到上限后,新調用會阻塞,此時消費者可能會超時,該屬性配置在<dubbo:method/>上則是針對指定方法的,配置在<dubbo:service/>上則是針對整個服務
Spring Boot中使用Dubbo
總步驟
一個Dubbo項目至少應該由三個工程構成:包含Service接口、實體類、常量類、工具類等的commons工程;包含Service實現類、Dao接口、Mapper映射文件的服務提供者serviceDao工程;包含SpringMVC的處理器類的服務消費者userWeb工程。其中commons工程就是一個普通的Maven-java工程,另外兩個都是Spring Boot的web工程。
服務提供者工程定義
- 添加zkClient依賴、Dubbo與Spring Boot整合依賴,以及commons工程依賴
- 在入口類上加上@EnableDubboConfiguration注解,開啟Dubbo自動配置
- 在主配置文件中添加Spring.application.name屬性,指定提供者應用名稱;添加spring.dubbo.registry屬性,指定注冊中心
- 在Service實現類上添加Dubbo的@Service注解,以及@Component注解
服務消費者工程定義
- 添加zkClient依賴、Dubbo與Spring Boot整合依賴,及commons工程依賴
- 在入口類上添加@EnableDubboConfiguration注解,開啟Dubbo自動配置
- 在主配置文件中添加spring.application.name屬性,指定提供者應用名稱;添加spring.dubbo.registry屬性,指定注冊中心
工程搭建
公共項目(4-common)
項目結構
pom.xml
<?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>com.cyb</groupId> <artifactId>4-common</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>13</maven.compiler.source> <maven.compiler.target>13</maven.compiler.target> </properties> <dependencies> <!--lombok依賴 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency> </dependencies> </project>
EmployeePo.java
package com.cyb.bean; import lombok.Data; import java.io.Serializable; @Data public class EmployeePo implements Serializable { private Integer id; private String name; private Integer age; }
EmployeeService.java
package com.cyb.service; import com.cyb.bean.EmployeePo; public interface EmployeeService { void addEmployee(EmployeePo employee); EmployeePo findEmployeeById(int id); int findEmployeeCount(); }
Install
提供者(4-provider)
新建Spring Boot工程
項目結構
EmployeeDao.java
package com.cyb.provider.dao; import com.cyb.bean.EmployeePo; import org.apache.ibatis.annotations.Mapper; @Mapper public interface EmployeeDao { void insertEmployee(EmployeePo employeePo); EmployeePo selectEmployeeById(int id); int selectEmployeeCount(); }
EmployeeDao.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cyb.provider.dao.EmployeeDao"> <insert id="insertEmployee"> insert into employee (name,age) values (#{name},#{age}) </insert> <select id="selectEmployeeById" resultType="com.cyb.bean.EmployeePo"> select id,name,age from employee where id=#{id} </select> <select id="selectEmployeeCount" resultType="int"> select count(1) from employee </select> </mapper>
EmployeeServiceImpl.java
package com.cyb.provider.service; import com.alibaba.dubbo.config.annotation.Service; import com.cyb.bean.EmployeePo; import com.cyb.provider.dao.EmployeeDao; import com.cyb.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.concurrent.TimeUnit; @Service //dubbo的Service,表示Dubbo服務的提供者 @Component public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeDao dao; @Autowired private RedisTemplate<Object, Object> redisTemplate; @CacheEvict(value = "realTimeCache", allEntries = true) // 清除緩存,實際生產環境就這樣玩,因為每個實體類設置不同的緩存區空間,范圍小,清除緩存好操作 @Transactional @Override public void addEmployee(EmployeePo employee) { dao.insertEmployee(employee); } //@Cacheable(value = "realTimeCache", key = "'employee_'+#id") @Cacheable(value = "realTimeCache") //用了自動生成key,此處可以去掉key // 先會去緩存中查下key是否存在,存在:則直接拿緩存中的數據;不存在:去數據庫中查,查完將結果放入緩存中 @Override public EmployeePo findEmployeeById(int id) { return dao.selectEmployeeById(id); } //使用雙重檢測鎖,解決熱點緩存問題 //雙重檢測鎖,解決了高並發下,對數據庫訪問的壓力!!!! //熱點緩存腦補,請參考:https://www.jianshu.com/p/6e37a1a9c160 @Override public int findEmployeeCount() { //獲取Redis操作對象 BoundValueOperations<Object, Object> ops = redisTemplate.boundValueOps("count"); //從緩存中讀取數據 Object count = ops.get(); if (count == null) { synchronized (this) { count = ops.get(); if (count == null) { //從DB中查詢 count = dao.selectEmployeeCount(); //將查詢的數據,寫入Redis緩存,並設置到期時限 ops.set(count, 10, TimeUnit.SECONDS); } } } return (int) count; } }
ProviderApplication.java
package com.cyb.provider; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableTransactionManagement //開啟事務 @SpringBootApplication @EnableCaching //開啟緩存 @EnableDubboConfig //開啟Dubbo自動配置 @EnableDubbo public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
application.properties
server.port=8899
# 注冊映射文件
mybatis.mapper-locations=classpath:com/cyb/provider/dao/EmployeeDao.xml
# 注冊實體類別名
mybatis.type-aliases-package=com.cyb.bean.EmployeePo
# 注冊數據源類型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 數據庫連接字符串
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/cyb
spring.datasource.username=root
spring.datasource.password=root
# 控制日志顯示格式
logging.pattern.console=%leven %msg%n
logging.level.root=warn
# 格式:logging.level.dao層命名空間
logging.level.com.cyb.provider.dao=debug
# 連接redis
spring.redis.host=192.168.1.108
spring.redis.port=6379
spring.redis.password=root
# 連接redis集群,redis利用哨兵機制實現高可用
# spring.redis.sentinel.master=mymaster
# spring.redis.sentinel.nodes=sentinel1:6370,sentinel2:6371,sentinel3:6372
# 指定緩存類型
spring.cache.type=redis
# 設置緩存名稱
spring.cache.cache-names=realTimeCache
# 注冊Dubbo相關配置
dubbo.application.name=provider
dubbo.registry.protocol=zookeeper
dubbo.registry.address=192.168.1.108:2181
dubbo.scan.base-packages=com.cyb.provider.service
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cyb</groupId> <artifactId>4-servicedata-provider</artifactId> <version>0.0.1-SNAPSHOT</version> <name>4-servicedata-provider</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>13</java.version> </properties> <dependencies> <!--自定義工程依賴--> <dependency> <groupId>com.cyb</groupId> <artifactId>4-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--zkClient客戶端依賴--> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> <!--移除日志版本依賴--> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <!--spring boot與dubbo整合依賴--> <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <!--Spring Boot與redis依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!--Druid連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!--mysql驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--Mybatis與Spring Boot整合依賴,必須要版本號 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <resources> <!--注冊dao包下mybatis映射文件為資源目錄 --> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>
消費者(4-consumer)
新建Spring Boot工程
項目結構
SomeController.java
package com.cyb.consumer.controller; import com.alibaba.dubbo.config.annotation.Reference; import com.cyb.bean.EmployeePo; import com.cyb.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class SomeController { @Reference // @Autowired private EmployeeService service; @RequestMapping("home") public String registerHandler(String name, int age, Model model) { model.addAttribute("name", name); model.addAttribute("age", age); return "home"; } @RequestMapping("/rows") public String GetCountHandle(Model model) { model.addAttribute("rows",service.findEmployeeCount()); return "/rows.jsp"; } @RequestMapping("/find") @ResponseBody public EmployeePo findHandle(int id){ return service.findEmployeeById(id); } @RequestMapping("/count") @ResponseBody public int countHandle(Model model){ int rec=service.findEmployeeCount(); return rec; } }
ConsumerApplication.java
package com.cyb.consumer; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubboConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableDubboConfig @EnableDubbo public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
application.properties
server.port=8800
# 視圖的前綴后后綴
#spring.mvc.view.prefix=/
#spring.mvc.view.suffix=.jsp
# 注冊Dubbo相關配置
dubbo.application.name=consumer
dubbo.registry.protocol=zookeeper
dubbo.registry.address=192.168.1.108:2181
dubbo.scan.base-packages=com.cyb.consumer.controller
rows.jsp
<%-- Created by IntelliJ IDEA. User: chenyanbin Date: 2020/3/16 Time: 1:22 下午 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 數據庫行數:${rows} </body> </html>
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cyb</groupId> <artifactId>4-web-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>4-web-consumer</name> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>13</java.version> </properties> <dependencies> <!--自定義工程依賴--> <dependency> <groupId>com.cyb</groupId> <artifactId>4-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--zkClient客戶端依賴--> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> <!--spring boot與dubbo整合依賴--> <dependency> <groupId>com.alibaba.spring.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <resources> <!--注冊webapp目錄為資源目錄 --> <resource> <directory>src/main/webapp</directory> <targetPath>META-INF/resources</targetPath> <includes> <include>**/*.*</include> </includes> </resource> </resources> </build> </project>
linux配置
redis配置
zookeeper配置
linux啟動服務
數據庫(Mysql)
項目演示
項目源碼下載
鏈接:https://pan.baidu.com/s/1fii6As5638pwO_trZ6Bsjw 密碼:xot2
Dubbo監控平台的部署與使用
項目下載
官網地址:http://dubbo.apache.org/zh-cn/
百度雲盤地址
鏈接:https://pan.baidu.com/s/1P0QOhOz3-FeuPpR5fUjakw 密碼:j0ek
下面需要使用控制台,演示用的mac電腦的終端,前期需在mac上安裝maven,還不會的小伙伴,請看我另一篇博客,點我直達
第一次打包會下載大量文件,安裝過程中漫長,請耐心等待,請看我另一篇博客,點我直達
控制台打包
注意:打包前,需要改配置文件,修改zookeeper的ip地址!!!!!!
注:第一次打包,需下載很多包,耐心等待!!!!