前提提示
飞书文档,老师档案
https://b11et3un53m.feishu.cn/wiki/R4Sdwvo8Si4kilkSKfscgQX0niB
1. Nacos
1.导入依赖
1 2 3 4 5
| <!--nacos 服务注册发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
|
2.配置文件连接Nacos
配置自己的nacos虚拟机地址,Nacos根据application下的name注册
1 2 3 4 5 6
| spring: application: name: cart-service cloud: nacos: server-addr: 172.16.207.227:8848
|
2. DiscoverClient
配合Nacos使用Spring封装好的Client
- 自动注入
1 2 3 4
| @RequiredArgsConstructor private final DiscoveryClient discoveryClient;
|
- 简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| List<ServiceInstance> services = discoveryClient.getInstances("item-service");
if (services.isEmpty()){ return; }
ServiceInstance instance = services.get(RandomUtil.randomInt(services.size()));
URI uri = instance.getUri();
ResponseEntity<List<ItemDTO>> response = restTemplate.exchange( uri + "/items?ids={ids}", HttpMethod.GET, null, new ParameterizedTypeReference<List<ItemDTO>>() { }, Map.of("ids", CollUtils.join(itemIds, ",")) );
if (!response.getStatusCode().is2xxSuccessful()){ return; }
List<ItemDTO> items = response.getBody();
if (CollUtils.isEmpty(items)) { return; }
|
3. OpenFeign,优化Client
1. 导入依赖
1 2 3 4 5 6 7 8 9 10
| <!--openFeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--负载均衡器--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
|
2. 使用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1. 启动项开关 openFeign开关,basePackages为扫描的包,防止不同模块下Client不能注册为Bean @EnableFeignClients(basePackages = "com.hmall.api.client")
2. FeignClient客户端写法 @FeignClient("item-service") public interface ItemClient {
@GetMapping("/items") List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
3. 使用方法 List<ItemDTO> items = itemClient.queryItemByIds(itemIds);
|
3. 优化连接池
默认连接池为Client,效率不高
1 2 3 4 5 6 7 8 9 10 11 12
| 1. 引入okhttp的依赖 <!--OK http 的依赖 --> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-okhttp</artifactId> </dependency>
2. 配置文件开启连接池 feign: okhttp: enabled: true # 开启OKHttp功能
|
4. 最佳使用方法
参考飞书文档
https://b11et3un53m.feishu.cn/wiki/R4Sdwvo8Si4kilkSKfscgQX0niB
5.配置日志
- 在通用模块下新建config包
注册Bean添加日志1 2 3 4 5 6 7 8 9 10
| package com.hmall.api.config; import feign.Logger; import org.springframework.context.annotation.Bean;
public class DefaultFeignConfig { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.FULL; } }
|
4. 网关
通过使用网关将前端的路径保持不变并传递当前登录用户的信息
一般新建一个模块,前端发来请求,网关先验证是否携带有效jwt令牌,若携带则根据前端的路径判断网关将这次请求发送到哪一个微服务中并且将令牌添加到请求头中发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| 1.添加依赖
<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
2.导入jwt相关配置信息和问价和工具类
3.在配置文件中写入不做用户验证拦截,要放行的路径 hm: jwt: location: classpath:hmall.jks alias: hmall password: hmall123 tokenTTL: 30m auth: excludePaths: - /search
|
5. 通过配置类实现微服务之间传输token
将token信息传入openFegin中的请求头中传输token信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| 1.在通用模块通过拦截器将请求头中的token添加到ThreadLocal中 public class UserInfoInterceptors implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userId = request.getHeader("user-info"); if (StrUtil.isNotBlank(userId)){ UserContext.setUser(Long.valueOf(userId)); } return true; }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserContext.removeUser(); } }
2. 添加拦截器 因为已经在网关中验证token合法性所以全部放行 @Configuration @ConditionalOnClass(DispatcherServlet.class) public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new UserInfoInterceptors()); } }
不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是com.hmall.common.config,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。 基于SpringBoot的自动装配原理,我们要将其添加到resources目录下的META-INF/spring.factories文件中: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.hmall.common.config.MyBatisConfig,\ com.hmall.common.config.MvcConfig,\ com.hmall.common.config.JsonConfig
3. openFegin中获取并传递实现微服务间传递 public class DeafultFeginConf {
@Bean public Logger.Level feignLogger(){ return Logger.Level.HEADERS; }
@Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { Long user = UserContext.getUser(); if (user != null){ requestTemplate.header("user-info" , user.toString()); } } }; } }
4. 微服务启动项加入注解(不同模块需要) @EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DeafultFeginConf.class)
|
nacos实现配置共享
在nacos中写入配置文件,通过bootstrap获取。减少重复配置文件的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 1. 添加依赖 <!--nacos配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--读取bootstrap文件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
2. 在nacos中导入配置文件 详情看飞书:微服务02-3.1 配置管理 https:
3. bootstrap 原理是在启动时springboot先读取bootstrap.yaml文件在读取application.yaml spring: application: name: cart-service # 服务名称 profiles: active: dev cloud: nacos: server-addr: 172.16.207.227:8848 # nacos地址 config: file-extension: yaml # 文件后缀名 shared-configs: # 共享配置 - dataId: shared-jdbc.yaml # 共享mybatis配置 - dataId: shared-log.yaml # 共享日志配置 - dataId: shared-swagger.yaml # 共享日志配置
|
nacos实现热更新
本质是通过读取配置文件获取信息,比如将购物车最多商品数量写入nacos的配置文件,再通过读取实现业务功能。
因为bootstrap读取nacos中的配置文件时会同时读取${application.name}.yaml配置文件,所以我门只需要新建一个这个名字的配置文件并将信息写入即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1. nacos中的配置文件 hm: cart: maxItem: 7
2. 读取 @Component @Data @ConfigurationProperties(prefix = "hm.cart") public class CartProperties { private int maxItem; }
3. 后续即可使用 比如购物车最大商品数量:注入CartProperties,再比较时通过比较maxItem进行判断实现热更新,不需要重启微服务
|
sentinel线程隔离,熔断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 1. 引入依赖 <!--sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
2. 配置文件配置控制台 spring: cloud: sentinel: transport: dashboard: localhost:8090
3. openFegin整合sentinel(在管理页面将client增加为簇点) feign: sentinel: enabled: true # 开启feign对sentinel的支持
|
- openFegin中的FallBack
在服务熔断时,异常率过高时,直接调用错误的FallBack减小性能压力
FallBack本质是处理client调用异常情况,增加用户体验
失败降级处理1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 1. 创建FallBackFactory @Slf4j public class ItemClientFallback implements FallbackFactory<ItemClient> { @Override public ItemClient create(Throwable cause) { return new ItemClient() { @Override public List<ItemDTO> queryItemByIds(Collection<Long> ids) { log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause); return CollUtils.emptyList(); }
@Override public void deductStock(List<OrderDetailDTO> items) { throw new BizIllegalException(cause); } }; } }
2. 注册Bean hm-api模块中的com.hmall.api.config.DefaultFeignConfig类中将ItemClientFallback注册为一个Bean: public ItemClientFallback fallback(){ return new ItemClientFallback(); }
3. 使用FallBack 在注解中添加 @FeignClient(value = "item-service", fallBackFactory = ItemClientFallback.class) public interface ItemClient { @GetMapping("/items") List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
|
seata解决微服务事务问题
- TC - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM - 资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 1. 在docker中部署,需要和mysql连接并且创建需要的db,需要和nacos连接 ....
2. 引入依赖 <!--统一配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--读取bootstrap文件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <!--seata--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> </dependency>
3. nacos添加共享seata配置 seata: registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址 type: nacos # 注册中心类型 nacos nacos: server-addr: 192.168.150.101:8848 # nacos地址 namespace: "" # namespace,默认为空 group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUP application: seata-server # seata服务名称 username: nacos password: nacos tx-service-group: hmall # 事务组名称 service: vgroup-mapping: # 事务组与tc集群的映射关系 hmall: "default"
4. 全局事务注解入口 @GlobalTransactional注解就是在标记事务的起点,将来TM就会基于这个方法判断全局事务范围,初始化全局事务。
5. 四种模式 XA 规范 是 X/Open 组织定义的分布式事务处理(DTP,Distributed Transaction Processing)标准,XA 规范 描述了全局的TM与局部的RM之间的接口,几乎所有主流的数据库都对 XA 规范 提供了支持。 XA:失败就回滚,可能事务阻塞导致性能差。但是满足事务的ACID原则
AT模式同样是分阶段提交的事务模型,不过缺弥补了XA模型中资源锁定周期过长的缺陷。 AT:对各个事务生成快照,若报错则回滚并且回到快照时间。
|
es搜索
安装es和可视化控制台管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 1. 安装 docker run -d \ --name es \ -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \ -e "discovery.type=single-node" \ -v es-data:/usr/share/elasticsearch/data \ -v es-plugins:/usr/share/elasticsearch/plugins \ --privileged \ -p 9200:9200 \ -p 9300:9300 \ elasticsearch:7.12.1
2. 安装Kibana(控制台控制es) docker run -d \ --name kibana \ -e ELASTICSEARCH_HOSTS=http: --network=hm-net \ -p 5601:5601 \ kibana:7.12.1
|
加入IK分词器插件
1 2 3 4 5 6 7 8 9 10
| 1. 在线安装 docker exec -it es ./bin/elasticsearch-plugin install https:
2. 离线安装: 查看数据卷位置 docker volume inspect es-plugins
将插件解压到对应数据卷位置
重启es:docker restart es
|
IK分词器使用
1 2 3 4 5 6 7 8 9 10 11
| POST /_analyze { "analyzer": "ik_max_word", "text": "传智播客开设大学,真的泰裤辣!" }
POST /_analyze { "analyzer": "ik_smart", "text": "传智播客开设大学,真的泰裤辣!" }
|
索引库的CRUD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 1. 查询 GET /索引库名
2. 修改 PUT /索引库名/_mapping { "properties": { "新字段名":{ "type": "integer" } } }
3. 删除 DELETE /索引库名
4. 新增 POST /索引库名/_doc/文档id { "字段1": "值1", "字段2": "值2", "字段3": { "子属性1": "值3", "子属性2": "值4" }, }
5. 局部处理 POST /{索引库名}/_update/文档id { "doc": { "字段名": "新的值", } }
|
占位
占位