和傳統ssm整合--寫XML配置文件
搭建服務的提供者和服務的消費者,實現服務消費者跨應用遠程調用服務提供者
公共模塊抽取
- 公共模塊的抽取
服務的消費者遠程調用服務的提供者, 最起碼他自己要得到在服務提供者提供服務的那個類的引用, 那消費者和服務的一人一份,如果是集群就會翻倍,故抽取公共模塊,存放公共使用的類和接口
服務提供者
- 依賴
// 自定義的公共模塊
<dependency>
<groupId>com.changwu</groupId>
<artifactId>commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.3</version>
</dependency>
- 編寫提供服務的業務Service, 對接口進行具體的實現
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList() {
UserAddress a1= new UserAddress(1,"張三","北京市朝陽區");
UserAddress a2= new UserAddress(2,"李四","山東濟南");
return Arrays.asList(a1,a2);
}
}
- 編寫配置文件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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 暴露服務提供者, name=服務名(不能和其他服務名重復) -->
<dubbo:application name="user-service-provider" />
<!-- z指定zookeeper的地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 指定通信規則,通信協議, 通信端口. 服務消費者和dubbo之間的通信-->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 聲明需要暴露的服務接口 ref=服務的真正實現, 下面使用<bean>調用-->
<dubbo:service interface="com.changwu.service.UserService" ref="userService" />
<!-- 接口的實現 -->
<bean id="userService" class="com.changwu.service.impl.UserServiceImpl" />
<dubbo:monitor protocol="registry"></dubbo:monitor>
</beans>
schema配置參考手冊, 點擊查看全部標簽,及詳細解釋
補充: 屬性配置的重寫覆蓋優先級
- 優先級最高 JVM 啟動時 使用-D設置參數
- 次之,dubbo.xml
- 再次之 dubbo.properties
如下,是一個典型的dubbo.properties配置樣例。
dubbo.application.name=foo
dubbo.application.owner=bar
dubbo.registry.address=10.20.153.10:9090
- idea設置虛擬機啟動參數
- log4j配置文件,(不添加的話會有警告)
###set log levels###
log4j.rootLogger=info, stdout
###output to console###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
服務的消費者
- 依賴
// 自定義的公共模塊
<dependency>
<groupId>com.changwu</groupId>
<artifactId>commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
// zk的客戶端依賴 curator
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
- 編寫consumer.xml
編寫配置文件自己的服務名,配置注冊中心的地址,進而向注冊中心拉取服務的列表,配置當前的消費者中使用的哪些接口是通過遠程RPC調用實現的, 還可以配置監控中心查看服務的健康情況,彼此的調用情況,別忘了使用Spring注解還得配置包掃描
<?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://dubbo.apache.org/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-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 消費方應用名,用於計算依賴關系,不是匹配條件,不要與提供方一樣 -->
<dubbo:application name="order-service" />
<!--注冊中心地址 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 生成遠程服務代理,可以和本地bean一樣使用 userService -->
<dubbo:reference id="userService" interface="com.changwu.service.UserService" />
<!--添加包掃描-->
<context:component-scan base-package="com.changwu"></context:component-scan>
<!--配置監控中心,有下面兩種方式 1. 去注冊中心自動發現, 2. 直連模式-->
<dubbo:monitor protocol="registry"></dubbo:monitor>
<!-- <dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor>-->
</beans>
- 消費者調用服務提供者的實現
下面的@Service注解使用的Spring原生的
@Service // 沒有用dubbo的service注解
public class OrderServiceImpl implements OrderService {
@Autowired
UserService userService;
public List initOrder(String userId) {
// 查詢用戶的地址
System.out.println("userId == "+userId);
List<UserAddress> userAddressList = userService.getUserAddressList("1");
for (UserAddress userAddress : userAddressList) {
System.out.println(userAddress.getAdress());
}
return userAddressList;
}
}
- 啟動測試
public class MainApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = ioc.getBean(OrderService.class);
orderService.initOrder("1");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
整合Springboot
公共模塊
同樣重復使用類,接口放到中,然后在其它模塊引用
服務提供者
- 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.changwu</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--
dubbo整合進springboot
zookeeper,curate它都已經導入進來了
-->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
- 將provider.xml配置文件替換成application.properties
可以將xml的tag名和屬性名組合起來,用‘.’分隔。每行一個屬性
# 指定當前的服務, 一般為了防止重復,設置成當前module的名字
dubbo.application.name=provider
# 指定注冊中心的地址
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
# dubbo 使用的協議
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
# 原配置文件中暴露服務的名字,使用類似下面的方式,但是在SpringBoot中使用 @Service注解(dubbo的)
# dubbo.service.interface=com.changwu.service.UserService
# 監控中心
dubbo.monitor.protocol=registry
server.port=8082
- 服務提供者對接口進行實現
@Service使用的dubbo的接口
@Component
@Service //使用dubbo的Service 對外保留服務
public class UserServiceImpl implements UserService {
public List<UserAddress> getUserAddressList(String userId) {
UserAddress a1= new UserAddress(1,"張三","北京市朝陽區");
UserAddress a2= new UserAddress(2,"李四","山東濟南");
return Arrays.asList(a1,a2);
}
}
- 啟動類,開啟dubbo配置
@EnableDubbo
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class);
}
}
服務的消費者
- 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.changwu</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
- 使用application.properties配置文件替換consumer.xml
# 告訴注冊中心自己的名字
dubbo.application.name=consumer
# 注冊中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 配置監控中心
dubbo.monitor.protocol=registry
# 原來在配置文件中使用 dubbo:reference 配置遠程調用的接口,現在用注解
server.port=8081
- 遠程調用@Reference dubbo注解
@Service
public class OrderServiceImpl implements OrderService{
//@Autowired
@Reference // dubbo的注解
UserService userService;
public List<UserAddress> initOrder(String userId) {
return userService.getUserAddressList("1");
}
}
- 編寫Controller
- 啟動類, 開啟dubbo配置
@EnableDubbo
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class);
}
}
其他常用配置
示例, dubbo常用的配置示例
啟動時檢查
服務的消費者在啟動是會去檢查自己需要遠程調用的服務是否已經注冊到了 注冊中心中, 一旦檢查到注冊中心沒有檢查到即使沒有調用這個方法也會自動報錯而阻止Spring啟動,在開發時,可以選擇手動關掉這個配置
- 通過配置文件
配置某個服務啟動時檢查
在服務消費者中,關閉某個服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:reference interface="com.foo.BarService" check="false" />
統一配置全部服務啟動時不檢查
關閉所有服務的啟動時檢查 (沒有提供者時報錯):
<dubbo:consumer check="false" />
默認是true. 表示注冊中心不存在時報錯
關閉注冊中心啟動時檢查 (注冊訂閱失敗時報錯):
<dubbo:registry check="false" />
- 通過dubbo.properties
dubbo.reference.com.foo.BarService.check=false
dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false
- 通過JVM參數
java -Ddubbo.reference.com.foo.BarService.check=false
java -Ddubbo.reference.check=false
java -Ddubbo.consumer.check=false
java -Ddubbo.registry.check=false
超時設置
消費者遠程調用服務提供者, 服務提供者的實現邏輯可能存在大量的耗時操作,這是就可能存在大量的線程阻塞在這個方法上, 超時設置解決了這個問題,一旦在指定的時間內,依然沒有返回任何數據,同樣會立即返回,保證系統的可用
缺省使用dubbo:consumer的timeout, 而dubbo:cosumer中默認的超時時間是 1000ms
如下,設置超時時間為3秒
<!-- 生成遠程服務代理,可以和本地bean一樣使用 userService -->
<dubbo:reference id="userService" interface="com.changwu.service.UserService" timeout="3000"/>
從上圖中,我標記了他們的作用,最優先的就是方法級別, 接口次之 , 全局級別最低 , -- 相同級別的消費者設置優先,提供者設置次之
重試次數
一般超時配置timeout 和 重試次數retries 配合使用
調用失敗后,會根據重試的次數再次嘗試遠程調用, 重試次數不包含第一次,如果我們配置的3, 算上第一次,最多嘗試調用四次
如果服務提供者存在集群, 消費者就會輪詢集群進行重試
- 冪等次數
- 查詢,刪除,修改(特點是,同樣的請求,同樣的參數無論執行多少次,產生的結果都是一樣的), 設置重試次數
- 非冪等
- 新增,不設置冪等次數, retries=0
<!-- 生成遠程服務代理,可以和本地bean一樣使用 userService -->
<dubbo:reference id="userService" interface="com.changwu.service.UserService" retries="3" timeout="3000"/>
多版本
我們給系統的某些功能進行了升級,但是不能一下把升級后的代碼一次性全部適用到集群中的全部機器上,使用多版本控制,先把集群中的一小部分機器進行升級,沒有出現不可用現象再逐步拓展規模,最終完成全部替換
新舊版本的服務提供者全部繼承同一個接口com.foo.BarService , 通過ref指向不同的實現Bean
老版本服務提供者配置:
<dubbo:service interface="com.foo.BarService" version="1.0.0" ref="userService1" />
<bean id="userService1" class="xxx">
新版本服務提供者配置:
<dubbo:service interface="com.foo.BarService" version="2.0.0" ref="userService2"/>
<bean id="userService2" class="yyy">
老版本服務消費者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="1.0.0" />
新版本服務消費者配置:
<dubbo:reference id="barService" interface="com.foo.BarService" version="2.0.0" />
如果不需要區分版本,可以按照以下的方式配置 [1]:
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />
本地存根
如果想在服務的消費者發送遠程過程調用其他方法之前進行,進行參數的驗證,如,判空處理, 可以選擇使用本地存根
如, UserService 是某個服務提供者實現的, 消費者遠程調用這個服務,進行如下配置消費者在本地提供自己的實現,並判斷參數的合法性
public class UserServiceImpl implements UserService{
// 注入這個被服務提供者支持的接口
private final UserService userService;
// 提供構造函數
public UserServiceImpl(UserService userService) {
this.userService = userService;
}
@Override
public List<UserAddress> getUserAddressList(String userId) {
// 判空
if (!StringUtils.isEmpty(userId)){
return userService.getUserAddressList(userId);
}
return null;
}
}
- 配置文件
在 spring 配置文件中按以下方式配置:
# 是消費者在本地自己的實現 com.changwu.service.UserServiceImpl
<dubbo:service interface="com.changwu.service.UserServiceImpl" stub="true" />
或
<dubbo:service interface="com.foo.BarService" stub="com.changwu.service.UserServiceImpl" />
Dubbo和SpringBoot整合的三種方式
方法1
- 引入dubbo-starter
- 在主配置類上使用@EnableDubbo (指定 包掃描規則)
- 在application.properties配置屬性
- 服務提供者: 使用 @Service 暴露服務
- 服務消費者: 使用 @Reference 引用服務
方法2
如果還想添加諸如方法級別的配置,則保留dubboxml的配置文件
- 在啟動類上去掉@EnableDubbo注解
- 在啟動類上添加@ImportResource(localtion="classpath:provider/consumer.xml")
- 去掉 application.properties 中的有關dubbo配置
- 服務提供者使用 provider.xml 配置文件
- 服務消費者是有 consumer.xml 配置文件
方法3 注解配置
要求使用dubbo為2.6.3