1.Spring Cloudweb
Spring Cloud是一個工具集,集成了多種工具,來解決微服務中的各類問題
微服務的總體解決方案 微服務全家桶spring
微服務治理,服務註冊和發現 eureka
負載均衡、請求重試 ribbon
斷路器,服務降級、熔斷 hystrix
ribbon + hystrix 集成,並提供聲明式客戶端 feign
hystrix 數據監控 hystrix dashboard 和 turbine
API 網關,提供微服務的統一入口,並提供統一的權限驗證 zuul
配置中心 config
消息總線, 配置刷新 bus
鏈路跟蹤 sleuth+zipkin
...json
Spring Cloud不是一個解決單一問題的框架!!!api
2.開發環境
IDEA或STS
Lombok
Mavenspringboot
3.Spring Cloud和Dubbo的區別服務器
Dubbo
1.Dubbo只是一個遠程調用(RPC)框架
2.默認基於長鏈接,支持多種序列化格式網絡
Spring Cloud
1.框架集
2.提供了一整套微服務解決方案(全家桶)
3.基於http調用, Rest APIapp
4.service- 服務負載均衡
五.item service商品服務
1.新建項目
2.配置依賴pom.xml 添加commons依賴
3.配置application.yml
4.配置主程序
5.編寫代碼框架
業務實現層
@Slf4j
@Service
public class ItemServiceImpl implements ItemService {
@Override public List<Item> getItems(String orderId) { ArrayList<Item> list = new ArrayList<Item>(); list.add(new Item(1, "商品 1",1)); list.add(new Item(2, "商品 2",2)); list.add(new Item(3, "商品 3",3)); list.add(new Item(4, "商品 4",4)); list.add(new Item(5, "商品 5",5)); return list; } @Override public void decreaseNumbers(List<Item> list) { for(Item item : list) { log.info("減小庫存 - "+item); } }
}
控制層
@Slf4j
@RestController
public class ItemController {
@Autowired private ItemService itemService; @Value("${server.port}") private int port; @GetMapping("/{orderId}") public JsonResult<List<Item>> getItems(@PathVariable String orderId) { log.info("server.port="+port+", orderId="+orderId); List<Item> items = itemService.getItems(orderId); return JsonResult.ok(items).msg("port="+port); } @PostMapping("/decreaseNumber") public JsonResult decreaseNumber(@RequestBody List<Item> items) { itemService.decreaseNumbers(items); return JsonResult.ok(); }
}
Spring MVC接收參數的幾個註解
@RequestParam
1.表單參數,鍵值對參數
2.能夠接受get或post請求提交的參數
3.name1=value&name2=value2&name3=value3
@PathVariable
1.請求路徑參數
2.http://localhost:8080/123
http://localhost:8080/123/aa/bb
@RequestBody
1.post請求協議體中的數據
2.完整的接受協議中的json數據
六.user service用戶服務
1.新建項目
2.配置依賴pom.xml
3.配置yml文件
4.配置主程序
5.編寫代碼
業務層
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Value("${sp.user-service.users}") private String userJson; @Override public User getUser(Integer id) { log.info("users json string : "+userJson); List<User> list = JsonUtil.from(userJson, new TypeReference<List<User>>() {}); for (User u : list) { if (u.getId().equals(id)) { return u; } } return new User(id, "name-"+id, "pwd-"+id); } @Override public void addScore(Integer id, Integer score) { // 這裏增長積分 log.info("user "+id+" - 增長積分 "+score); }
}
控制層
@Slf4j
@RestController
public class UserController {
@Autowired private UserService userService; @GetMapping("/{userId}") public JsonResult<User> getUser(@PathVariable Integer userId) { log.info("get user, userId="+userId); User u = userService.getUser(userId); return JsonResult.ok(u); } @GetMapping("/{userId}/score") public JsonResult addScore( @PathVariable Integer userId, Integer score) { userService.addScore(userId, score); return JsonResult.ok(); }
}
七. order service訂單服務
業務層
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Override public Order getOrder(String orderId) { //TODO: 調用user-service獲取用戶信息 //TODO: 調用item-service獲取商品信息 Order order = new Order(); order.setId(orderId); return order; } @Override public void addOrder(Order order) { //TODO: 調用item-service減小商品庫存 //TODO: 調用user-service增長用戶積分 log.info("保存訂單:"+order); }
}
控制層
@Slf4j
@RestController
public class OrderController {
@Autowired private OrderService orderService; @GetMapping("/{orderId}") public JsonResult<Order> getOrder(@PathVariable String orderId) { log.info("get order, id="+orderId); Order order = orderService.getOrder(orderId); return JsonResult.ok(order); } @GetMapping("/") public JsonResult addOrder() { //模擬post提交的數據 Order order = new Order(); order.setId("123abc"); order.setUser(new User(7,null,null)); order.setItems(Arrays.asList(new Item[] { new Item(1,"aaa",2), new Item(2,"bbb",1), new Item(3,"ccc",3), new Item(4,"ddd",1), new Item(5,"eee",5), })); orderService.addOrder(order); return JsonResult.ok(); }
}
八 eureka 註冊與發現
server:
port: 2001
eureka:
server:
enable-self-preservation: false 關閉保護模式
instance:
hostname: eureka1 eureka集羣服務器之間 經過此標籤區分
client:
#不一樣自身註冊 不從自身拉取信息 register-with-eureka: false fetch-registry: false
eureka註冊中心
做用:服務註冊和發現
提供者(Provider)
向註冊中心註冊本身的地址
消費者(Consumer)
從註冊中心發現其餘服務
eureka的運行機制
註冊 一次次反覆鏈接eureka 直到註冊成功爲止
拉取 每隔30秒拉取一次註冊表 更新註冊信息
心跳 每30秒發送一次心跳 3次收不到心跳 ureka會刪除這個服務
自我保護模式 特殊狀況 因爲網絡不穩定15分鐘內85%服務器出現心跳異常
保護全部的註冊信息不刪除
網絡恢復後 能夠自動退出保護模式
開發測試期間 能夠關閉保護模式
搭建eureka服務
1.eureka server依賴
2.yml文件配置
關閉保護模式
主機名(集羣中區分每臺服務器)
針對單臺服務器,不向本身註冊,不從本身拉取
3.啓動類
@EnableEurekaServer 觸發eureka服務器的自動配置
服務提供者
2.yml配置eureka鏈接地址
主程序添加@EnableEurekaServer註解
修改hosts文件
127.0.0.1 eureka1
127.0.0.1 eureka2
eureka和"服務提供者"的高可用(集羣)
遠程調用
RestTemplate
springboot 提供的遠程調用工具,相似 HttpClient
RestTemplate 對http Rest API 調用作了高度封裝,只須要調用一個方法就能夠完成請求、響應、json轉換
用 RestTemplate 調用 2,3,4 項目
Ribbon
springcloud 提供的工具,對 RestTemplate 進行了加強封裝,提供了負載均衡和重試的功能
item-service 高可用
啓動參數 --server.port 能夠覆蓋yml中的端口配置
配置啓動參數
--server.port=8001
複製一份
--server.port=8002
eureka高可用
添加兩個服務器的profile配置文件
配置啓動參數和端口
--spring.profiles.active=eureka1 --server.port=2001
--spring.profiles.active=eureka2 --server.port=2002
eureka客戶端註冊時,向兩個服務器註冊
ribbon 服務消費者
ribbon 提供了負載均衡和重試功能 它底層是使用RestTemplate進行Rest api調用
RestTemplate
RestTemplate是SpringBoot提供的一個Rest遠程調用工具
經常使用方法
getForObject() 執行get請求
postForObject() 執行post請求
1.新建ribbon項目
2.pom.xml
添加Eureka Discovery Client 和 web 依賴
3.yml文件
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url: defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
4.主程序
@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {
//建立 RestTemplate 實例,並存入 spring 容器
@Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(Sp06RibbonApplication.class, args); }
}
5.controller
@RestController
public class RibbonController {
@Autowired private RestTemplate rt; @GetMapping("/item-service/{orderId}") public JsonResult<List<Item>> getItems(@PathVariable String orderId) { //向指定微服務地址發送 get 請求,並得到該服務的返回結果 //{1} 佔位符,用 orderId 填充 return rt.getForObject("http://localhost:8001/{1}", JsonResult.class, orderId); } @PostMapping("/item-service/decreaseNumber") public JsonResult decreaseNumber(@RequestBody List<Item> items) { //發送 post 請求 return rt.postForObject("http://localhost:8001/decreaseNumber", items, JsonResult.class); } / @GetMapping("/user-service/{userId}") public JsonResult<User> getUser(@PathVariable Integer userId) { return rt.getForObject("http://localhost:8101/{1}", JsonResult.class, userId); } @GetMapping("/user-service/{userId}/score") public JsonResult addScore( @PathVariable Integer userId, Integer score) { return rt.getForObject("http://localhost:8101/{1}/score?score={2}", JsonResult.class, userId, score); } / @GetMapping("/order-service/{orderId}") public JsonResult<Order> getOrder(@PathVariable String orderId) { return rt.getForObject("http://localhost:8201/{1}", JsonResult.class, orderId); } @GetMapping("/order-service") public JsonResult addOrder() { return rt.getForObject("http://localhost:8201/", JsonResult.class); }
}
6.啓動 並訪問測試
ribbon負載均衡和測試
負載均衡
修改sp06-ribbon項目
1.添加ribbon起步依賴
2.RestTemplate設置@loadBalanced
3.訪問路徑設置爲服務id
@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {
@LoadBalanced //負載均衡註解 @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(Sp06RibbonApplication.class, args); }
}
訪問路徑設置問服務id
將控制層的本地地址和端口改成服務的id
例如 "http://item-service/{1}"
pom.xml文件中添加spring-retry依賴
<dependency>
<groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId>
</dependency>
yml文件配置ribbon重試
spring:
application:
name: ribbon
server:
port: 3001
eureka:
client:
service-url: defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
ribbon:
MaxAutoRetriesNextServer: 2 更換實例的次數
MaxAutoRetries: 1 當前實例重試次數 嘗試失敗會更換下一個實例
OkToRetryOnAllOperations: true 可不寫 默認支隊GET請求重試 默認爲false 當設置爲true時 對POST等全部的類型請求進行都重試
主程序設置RestTemplate的請求工廠的超時屬性
@EnableDiscoveryClient
@SpringBootApplication
public class Sp06RibbonApplication {
@LoadBalanced @Bean public RestTemplate getRestTemplate() { SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory(); f.setConnectTimeout(1000); f.setReadTimeout(1000); return new RestTemplate(f); //RestTemplate 中默認的 Factory 實例中,兩個超時屬性默認是 -1, //未啓用超時,也不會觸發重試 //return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(Sp06RibbonApplication.class, args); }
}
item-service 的 ItemController 添加延遲代碼,以便測試 ribbon 的重試機制
///--設置隨機延遲
if(Math.random()<0.6) { long t = new Random().nextInt(5000); log.info("item-service-"+port+" - 暫停 "+t); Thread.sleep(t); }