Apache Dubbo |ˈdʌbəʊ| 是一款高效能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向介面的遠端方法呼叫,智慧容錯和負載均衡,以及服務自動註冊和發現。
說明:介面專案一般定義公共的部分,並且被第三方依賴.
package com.jt.dubbo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.dubbo.mapper.UserMapper;
import com.jt.dubbo.pojo.User;
@Service(timeout=3000) //3秒超時 內部實現了rpc
//@org.springframework.stereotype.Service//將物件交給spring容器管理
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
System.out.println("我是第一個服務的提供者");
return userMapper.selectList(null);
}
@Override
public void saveUser(User user) {
userMapper.insert(user);
}
}
server:
port: 9000 #定義埠
spring:
datasource:
#引入druid資料來源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#關於Dubbo設定
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路徑 掃描dubbo註解
application: #應用名稱
name: provider-user #一個介面對應一個服務名稱 一個介面可以有多個實現
registry: #註冊中心 使用者獲取資料從機中獲取 主機只負責監控整個叢集 實現資料同步
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
protocol: #指定協定
name: dubbo #使用dubbo協定(tcp-ip) web-controller直接呼叫sso-Service
port: 20880 #每一個服務都有自己特定的埠 不能重複.
mybatis-plus:
type-aliases-package: com.jt.dubbo.pojo #設定別名包路徑
mapper-locations: classpath:/mybatis/mappers/*.xml #新增mapper對映檔案
configuration:
map-underscore-to-camel-case: true #開啟駝峰對映規則
package com.jt.dubbo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.dubbo.pojo.User;
import com.jt.dubbo.service.UserService;
@RestController
public class UserController {
//利用dubbo的方式為介面建立代理物件 利用rpc呼叫
@Reference
private UserService userService;
/**
* Dubbo框架呼叫特點:遠端RPC呼叫就像呼叫自己本地服務一樣簡單
* @return
*/
@RequestMapping("/findAll")
public List<User> findAll(){
//遠端呼叫時傳遞的物件資料必須序列化.
return userService.findAll();
}
@RequestMapping("/saveUser/{name}/{age}/{sex}")
public String saveUser(User user) {
userService.saveUser(user);
return "使用者入庫成功!!!";
}
}
server:
port: 9001
dubbo:
scan:
basePackages: com.jt
application:
name: consumer-user #定義消費者名稱
registry: #註冊中心地址
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
答:由於zk的幫助,使得程式永遠可以存取正確的伺服器.並且當服務重新啟動時,duboo有服務的自動發現功能,消費者不需要重新啟動即可以存取新的服務.
答: 使用者的存取不受影響,由於消費者在本地儲存服務列表資訊,當存取故障機時,自動的將標識資訊改為down屬性.
1.使用者端負載均衡
Dubbo/SpringCloud等微服務架構
2.伺服器端負載均衡
說明:使用者端發起請求之後,必須由統一的伺服器進行負載均衡,所有的壓力都在伺服器中.
NGINX
@RestController
public class UserController {
//利用dubbo的方式為介面建立代理物件 利用rpc呼叫
//@Reference(loadbalance = "random") //預設策略 負載均衡隨機策略
//@Reference(loadbalance = "roundrobin") //輪詢方式
//@Reference(loadbalance = "consistenthash") //一致性hash 消費者繫結伺服器提供者
@Reference(loadbalance = "leastactive") //挑選當前負載小的伺服器進行存取
private UserService userService;
}
<!--引入dubbo設定 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
server:
port: 8093
servlet:
context-path: /
spring:
datasource:
#引入druid資料來源
#type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#mybatis-plush設定
mybatis-plus:
type-aliases-package: com.jt.pojo
mapper-locations: classpath:/mybatis/mappers/*.xml
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.jt.mapper: debug
#關於Dubbo設定
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路徑 掃描dubbo註解
application: #應用名稱
name: provider-user #一個介面對應一個服務名稱 一個介面可以有多個實現
registry: #註冊中心 使用者獲取資料從機中獲取 主機只負責監控整個叢集 實現資料同步
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
protocol: #指定協定
name: dubbo #使用dubbo協定(tcp-ip) web-controller直接呼叫sso-Service
port: 20880 #每一個服務都有自己特定的埠 不能重複.
測試Dubbo伺服器啟動是否正常.
server:
port: 8092
spring: #定義springmvc檢視解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
dubbo:
scan:
basePackages: com.jt
application:
name: consumer-web #定義消費者名稱
registry: #註冊中心地址
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
根據url地址說明請求為同域請求.
引數資訊:
說明:根據分析獲取返回值資料資訊應該為SysResult物件
/**
* 需求: 實現使用者資訊註冊
* 1.url請求地址: http://www.jt.com/user/doRegister
* 2.請求引數: {password:_password,username:_username,phone:_phone},
* 3.返回值結果: SysResult物件
*/
@RequestMapping("/doRegister")
@ResponseBody //將資料轉化為JSON
public SysResult saveUser(User user){
//消費者給予dubbo協定將user物件進行遠端網路資料傳輸.
userService.saveUser(user);
return SysResult.success();
}
/**
* 注意事項:
* 1.暫時使用電話號碼代替郵箱
* 2.密碼進行md5加密.
* 3.入庫操作注意事務控制
* @param user
*/
@Override
public void saveUser(User user) {
String md5Pass =
DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setEmail(user.getPhone())
.setPassword(md5Pass);
userMapper.insert(user);
}
說明:在zk中資料的儲存採用樹形結構的方式儲存
命令: [root@localhost bin]# sh zkCli.sh
查詢命令: ls /…
說明: 如果採用SESSION的方式實現使用者的登入操作,由於nginx負載均衡的策略,使用者可以存取不同的伺服器.但是Session不能共用,所以導致使用者頻繁的登入. 使用者的體驗不好.
單點登入(SingleSignOn,SSO),就是通過使用者的一次性鑑別登入。當使用者在身份認證伺服器上登入一次以後,即可獲得存取單點登入系統中其他關聯絡統和應用軟體的許可權,同時這種實現是不需要管理員對使用者的登入狀態或其他資訊進行修改的,這意味著在多個應用系統中,**使用者只需一次登入就可以存取所有相互信任的應用系統。**這種方式減少了由登入產生的時間消耗,輔助了使用者管理,是目前比較流行的 [1]
實現步驟:
1.當使用者輸入使用者名稱和密碼點選登入時,將請求傳送給JT-WEB消費者伺服器.
2.JT-WEB伺服器將使用者資訊傳遞給JT-SSO單點登入系統完成資料校驗.
3.如果登入成功,則動態生成金鑰資訊,將user資料轉化為json.儲存到redis中. 注意超時時間的設定.
4.JT-SSO將登入的憑證 傳給JT-WEB伺服器.
5.JT-WEB伺服器將使用者金鑰TICKET資訊儲存到使用者的cookie中 注意超時時間設定.
6.如果登入不成功,則直接返回錯誤資訊即可.
/**
* 完成使用者登入操作
* 1.url地址: http://www.jt.com/user/doLogin?r=0.9309436837648131
* 2.引數: {username:_username,password:_password},
* 3.返回值結果: SysResult物件
*
* 4.Cookie:
* 4.1 setPath("/") path表示如果需要獲取cookie中的資料,則url地址所在路徑設定.
* url:http://www.jt.com/person/findAll
* cookie.setPath("/"); 一般都是/
* cookie.setPath("/person");
* 4.2 setDomain("xxxxx") 設定cookie共用的域名地址.
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user, HttpServletResponse response){
String ticket = userService.doLogin(user);
if(StringUtils.isEmpty(ticket)){
//說明使用者名稱或者密碼錯誤
return SysResult.fail();
}else{
//1.建立Cookie
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(7*24*60*60); //設定cookie存活有效期
cookie.setPath("/"); //設定cookie有效範圍
cookie.setDomain("jt.com"); //設定cookie共用的域名 是實現單點登入必備要素
response.addCookie(cookie);
return SysResult.success(); //表示使用者登入成功!!
}
}
/**
* 1.獲取使用者資訊校驗資料庫中是否有記錄
* 2.有 開始執行單點登入流程
* 3.沒有 直接返回null即可
* @param user
* @return
*/
@Override
public String doLogin(User user) { //username/password
//1.將明文加密
String md5Pass =
DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Pass);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
//根據物件中不為null的屬性當做where條件.
User userDB = userMapper.selectOne(queryWrapper);
if(userDB == null){
//使用者名稱或密碼錯誤
return null;
}else{ //使用者名稱和密碼正確 實現單點登入操作
String ticket = UUID.randomUUID().toString();
//如果將資料儲存到第三方 一般需要脫敏處理
userDB.setPassword("123456你信不??");
String userJSON = ObjectMapperUtil.toJSON(userDB);
jedisCluster.setex(ticket, 7*24*60*60, userJSON);
return ticket;
}
}