一、單體架構
?測試高并發軟件
二、微服務
?三、SpringCloud

四、微服務拆分
黑馬商城模塊:
服務拆分原則:
拆分服務:
獨立project:
maven聚合:
拆分案例:
遠程調用:
package com.hmall.cart.config;import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@org.springframework.context.annotation.Configuration
public class Configuration {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}
@Service
@RequiredArgsConstructor //自動生成必備參數的構造函數
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {/*private final IItemService itemService;*/// @Autowired Spring不建議使用@Autowiredprivate final RestTemplate restTemplate;/*Spring建議使用構造函數注入*/
/* public CartServiceImpl(RestTemplate restTemplate){this.restTemplate=restTemplate;}*/
}
private void handleCartItems(List<CartVO> vos) {// 1.獲取商品idSet<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查詢商品//List<ItemDTO> items = itemService.queryItemByIds(itemIds);//2.1 利用RestTemplate發送http請求,得到http響應ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {}, //利用反射拿到這個對象上的泛型Map.of("ids", CollUtil.join(itemIds, ",")));//2.2解析響應if(!response.getStatusCode().is2xxSuccessful()){//查詢失敗 直接結束return;}List<ItemDTO> items = response.getBody();if (CollUtils.isEmpty(items)) {return;}// 3.轉為 id 到 item的mapMap<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));// 4.寫入vofor (CartVO v : vos) {ItemDTO item = itemMap.get(v.getItemId());if (item == null) {continue;}v.setNewPrice(item.getPrice());v.setStatus(item.getStatus());v.setStock(item.getStock());}}
邏輯:
五、服務治理
上文提到的遠程調用帶來的問題:
注冊中心:
Nacos注冊中心:
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim
服務注冊:
多實例部署:
服務發現:
六、OpenFeign
快速入門:
———————————————————————————————————————————
———————————————————————————————————————————
請求路徑參數通過SpringMVC注解@GetMapping以及@RequestParam完成替代
請求參數通過調用該接口方法時傳遞的參數完成替代
返回值類型通過該接口定義的抽象方法的返回值類型完成替代
從而實現整體替代,簡化代碼
package com.hmall.cart.client;import com.hmall.cart.domain.dto.ItemDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection;
import java.util.List;@FeignClient("item-service")
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
private final ItemClient itemClient; //自動注入private void handleCartItems(List<CartVO> vos) {// 1.獲取商品idSet<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查詢商品//2.1 根據服務名稱獲取服務的實例列表/* List<ServiceInstance> instances = discoveryClient.getInstances("item-service");if(CollUtil.isEmpty(instances)){//判斷為空 直接結束return;}//2.2 手寫負載均衡,從實例列表中挑選一個實例ServiceInstance instance = instances.get(RandomUtil.randomInt(0, instances.size()));URI uri = instance.getUri(); //主機地址 http://localhost:8081//List<ItemDTO> items = itemService.queryItemByIds(itemIds);//2.3 利用RestTemplate發送http請求,得到http響應ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(uri+"/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {}, //利用反射拿到這個對象上的泛型Map.of("ids", CollUtil.join(itemIds, ",")));//2.4解析響應if(!response.getStatusCode().is2xxSuccessful()){//查詢失敗 直接結束return;}List<ItemDTO> items = response.getBody();*/List<ItemDTO> items = itemClient.queryItemByIds(itemIds);if (CollUtils.isEmpty(items)) {return;}// 3.轉為 id 到 item的mapMap<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));// 4.寫入vofor (CartVO v : vos) {ItemDTO item = itemMap.get(v.getItemId());if (item == null) {continue;}v.setNewPrice(item.getPrice());v.setStatus(item.getStatus());v.setStock(item.getStock());}}
底層原理:
代碼中通過?itemClient?對象來調用接口方法時,實際上它是一個動態代理對象。
動態代理對象底層邏輯都是由 InvocationHandler 實現
這里的?FeignInvocationHandler?是 ReflectiveFeign 的一個內部類,實現了 InvocationHandler 接口,? ?InvocationHandler 接口中的 invoke 方法就是起到了代理的作用 : 所有的被代理對象中的所有業務(方法) 都會通過?invoke?方法實現代理,除了一些基本方法(比如 equals, hashCode ,toString)
InvocationHandler?接口的實現類 FeignInvocationHandler?中重寫對應 invoke? 從而實現代理的方法如下:
最后調用對應的方法發送請求(Client)
?
連接池:
OpenFeign底層發送請求使用的是?Client
OpenFeign整合并使用連接池步驟:
最佳實踐:
拆分的最佳方式: