# 学习内容SpringCloud  Hoxton.SR8   耐菲RabbitMQ分布式事务RocketMQDockerElasticswarchKubernetesLucene Solr# 一. ideaplugin EditStarters, Free Mybatis Plugin, Maven Helper中央仓库
## STS# 二. SpirngCloud  ## A. 本阶段内容SpirngCloud Hoxton.SR8      微服务Eureka                      注册中心Feign                       远程调用Feign + Ribbon              负载均衡Zuul                        网关Zuul + Ribbon               负载均衡Zuul + Hystrix              容错和限流HystrixDashboard + actuator          链路监控Turbine                     聚合日志Spring cloud config         配置中心## 服务ItemServiceApplicationUserServiceApplicationOrderServiceApplication    FeignEurekaApplciation                          http://eureka1:2001/ZuulApplication                            http://localhost:3001/item-service/item/23/?token=123HystrixDashboardApplication                http://localhost:4001/hystrix     ->    http://localhost:3001/actuator/hystrix.streamTurbineApplication                         http://localhost:5001/turbine.stream聚合了3001和3002          http://localhost:4001/hystrix  ->  http://localhost:5001/turbine.streamSpringCloudConfigApplication               http://localhost:6001/item-service/dev## 0. 集成多种工具,解决微服务中的各种问题- 注册和发现- Nacos- Eureka- 远程调用 - OpenFeign- 负载均衡- 重试- 系统容错和限流 - Sentinel, Hystrix- 降级- 熔断- 错误监控 - Hystrix Dashboard、Turbine- 配置中心 - Nacos、Config- 链路跟踪 - Sleuth、Zipkin## 1. 依赖 pom.xml> 打包方式<packaging>pom</packaging>> jacksonjson互转工具> lombok> javax.servlet-api  创建cookie> slf4j-api> commons-lang3apache的工具包> maven-compiler-pluginmaven插件## 2. 项目结构
springcloud1sp01-commonspojoservice(Interface)web.utilsp02-itemserviceservice(impl)controllersp03-userserviceservice(impl)controllersp04-orderserviceservice(impl)controller## 3. eureka 注册中心    --服务注册,服务发现,维护注册信息
> nacos, eureka, consul, etcd, zookeeper >*1* 注册中心业务:  把服务注册在里面, 服务注册 服务发现  服务A 调用 服务B, 先从注册中心获取注册表得到所有, 找到对应的服务地址. A 在注册中心得到 B 的服务地址 再调用B的业务 >*2* eureka:作为springboot服务a. 禁用自我保护模式    --在集群中                                 ---eureka:server:enable-self-preservation: falseb. 主机名 --                                                     ---instance:hostname: eureka1c. 不向自己注册, 不从自己拉取  --集群中多个eureka要互相注册拉取     ---client:register-with-eureka: false      fetch-registry: false>*3* eureka服务器搭建:1. 新建服务 sp05-eureka2. pom.xml  依赖: eureka server3. application.ymleureka:server:enable-self-preservation: falseinstance:hostname: eureka1client:register-with-eureka: falsefetch-registry: falseservice-url:defaultZone: http://eureka1:2001/eureka/# 集群节点服务器默认http://localhost:8761/eureka/a. 集群服务器之间, 通过hostname 区分不同的eurekab. eureka.server.enable-self-preservationeureka的自我保护状态,心跳失败的比例-15分钟内达到85%进入保护状态, 把实例注册信息保护起来, 不再注销任何微服务c. eureka.client.register-with-eureka=false不向自身注册d. eureka.client.fetch-registry=false不从自身拉取注册信息e. eureka.instance.lease-expiration-duration-in-seconds最后一次心跳后,间隔多久认定微服务不可用,默认904. 启动类注解:@EnableEurekaServer  --触发eureka服务器的自动配置### hosts: C:\Windows\System32\drivers\etc>*4* eureka客户端搭建  ---在需要在注册中心注册的服务中,配置- 02-item 03-user 04-order 配置1. pom.xml  eureka client依赖2. application.yml配置eureka server地址eureka:client:service-url:defaultZone: http://localhost:2001/eurekaeureka.instance.lease-renewal-interval-in-seconds心跳间隔时间,默认 30 秒defaultZone,默认位置,可以修改为具体地理位置,比如:beiJing, shangHai, shenZhen 等,表示 eureka 服务器的部署位置, 需要云服务器提供eureka.client.registry-fetch-interval-seconds拉取注册信息间隔时间,默认 30 秒3. 启动类注解@EnableDiscoveryClient>*5* eureka运行机制1. 注册: 客户端 反复连接服务器, 直到注册成功为止2. 拉取: 客户端 每30秒拉取注册表, 刷新注册表3. 心跳: 客户端 30秒发送一次, 服务端连续3次收不到-删除这个服务, 4. 自我保护模式: 15分钟内,85%服务器出现心跳异常(又一次未收到),     保护所有注册信息不删除,   服务端连续3次收不到心跳-不删除>*6* 高可用1. item-service 高可用  启动两个服务(不同端口)  8001 8002a. 打包package  java -jar item.jar                           使用的端口是yml中的8001java -jar item.jar --server.port=8002        使用的是设置的8002b.idea启动配置edit configuration -> program arguments -> --server.port=8001Sp02ItemServiceApplication-8002 -> copy configuration -> 80022. eureka高可用a. profile配置    profile名字就是eureka1application-eureka1.ymleureka:instance:hostname: eureka1client:register-with-eureka: true  #profile的配置会覆盖公用配置fetch-registry: true        #profile的配置会覆盖公用配置service-url: defaultZone: http://eureka2:2002/eureka  #eureka1启动时向eureka2注册b. 使用配置打包运行: java -jar eureka.jar --spring.profiles.active=eureka1idea启动配置: program arguments## 4. Feign   --远程调用
订单服务获取订单获取用户获取订单列表保存订单增加用户积分减少商品库存>*1* 订单服务a. 依赖: openfeignb. 启动类注解: @EnableFeignClientsc. 定义声明式客户端接口(远程调用服务接口)ItemClientUserClient1. 调用哪个服务  @FeignClient(name = "item-service")2. 调用哪个路径  @GetMapping("/{orderId}")3. 提交什么参数  JsonResult<List<Item>> getItems(@PathVariable String orderId);d. service使用feign来远程调用注入接口 @Autowiredprivate ItemClient itemClient;图标请求
@GetMapping("/favicon.ico")
public void ico(){}## 5. Feign 集成 ribbon
>*1* 默认实现负载均衡feign底层已经实现了, >*2* 默认实现重试调用远程服务时, 远程服务出错, 可以重试或者负载均衡a. 重试参数ribbon.MaxAutoRetries=0      --单台服务器的重试次数ribbon.MaxAutoRetriesNextServer=1    --更换服务器次数ribbon.ReadTimeout=1000    --发送请求后, 等待响应的超时时间ribbon.ConnectTimeout=1000   --与后台服务器建立网络连接的超时时间ribbon.OkToRetryOnAllOperations=false    --是否对所有类型请求都进行重试,默认只对get请求重试b. 测试延迟 ItemController## 6. Zuul API网关 a. zuul所有的功能都是通过过滤器实现的,前置过滤器 pre-filtes路由       routing后置        post错误      errorb. zuul的配置自动配置, 会从Spring容器发现这个过滤器实例, 自动完成配置>*0* 新模块 sp06-zuula. 依赖: eureka-client, zuul, sp01b. .yml配置路由-routes   --路径和后台服务之间的映射zuul:   # 默认配置-根据注册表设置routes:item-service: /item-service/**user-service: /user-service/**order-service: /order-service/**c. 启动类注解@EnableZuulProxy>*1* 功能统一的入口         --转发统一的权限校验集成ribbon集成hystrix>*2* 统一的权限校验   过滤器过滤器, 在过滤器中检查用户权限http://localhost:3001/item-service/item/fds123?token=fdjkslf13fd1s3a. 继承Zuul的过滤器    ZuulFilter, 实现方法filtertype() 过滤器类型, FilterConstants.PRE_TYPEfilterOrder() 过滤器顺序号, 前5个是默认的过滤器, 加在第6个在第5个过滤器中, 向上下文对象添加了serviceId属性, 后面的过滤器才能访问serviceId属性shouleFilter() 针对请求是否执行过滤代码, 实现: 判断调用的后台服务, 服务id获取服务id  RequestContext.getCurrentContext().get("FilterConstants.SERVICE_ID_KEY");run() 自定义过滤器具体代码实现请求可以执行 run(), 再在这里判断是否有权限没有权限  阻止继续调用requestContext.setSendZuulResponse(false);b. 注解 @Component>*3* 网关超时 GateWay Timeout  504## 7. zuul集成ribbon默认实现了负载均衡, 没有启动ribbon重试尽量步骤网关添加重试, 否则可能造成大面积服务器压力倍增启动重试(Zuul网关不推荐)a. 添加 spring-retry依赖b. yml配置 zuul.retryable=truec. 有默认重试参数, 可以修改配置对所有服务通用ribbon:MaxAutoRetries: 1     --单台服务器的重试次数MaxAutoRetriesNextServer: 1    --更换服务器次数只对item服务有用item-service:ribbon:MaxAutoRetries: 0## 8. zuul集成hystrix容错和限流     链路监控     网关出错--会调用hystrixa. 容错:降级: 当调用后天服务出错, 执行当前服务中一段 降级 代码, 返回降级结果b. 限流:熔断: 调用后台服务流量过大时, 后台服务出现故障, 可以断开链路, 减轻后天服务压力c. 降级:调用后台服务出错:   500, 后台服务不存在, 调用超时, 默认1秒实现:依赖: 间接依赖配置: 无代码: 实现 FallbackProvider 接口  @ComponentgetRoute()设置针对哪个后台服务进行降级*/null 对所有服务应用降级类item-service  只针对item服务应用降级类fallbackResponse()向客户端发回的降级响应- 错误提示- 缓存数据new ClientHttpResponse(){}zuul默认已经启动hystrix, 自动从容器中读取到实现了接口的实例, d. Hysrix超时默认1秒超时ribbon重试, Hysrix超时会自动配置成ribbon的最大超时时间设置超时时间:hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 500e. 熔断:后台服务流量过大, 出现故障, 发生条件: 10秒20次请求(必须首先满足), 50%失败执行降级(), 断路器打开后: 一段时间后,进入半开状态,  半开状态下,会尝试向后天服务发送一次客户端调用调用成功: f. zuul 降级 https://gitee.com/zhaoqing_lj/msapro2104/tree/master/springcloud1/sp06-zuul/src/main/java/cn/tedu/sp06/fallbackpg. 请求 报500http://localhost:3001/order-service/order/1zuul -> order -> { user, item }  OrderFallback.java  ---降级代码code: 500,msg: "后台服务出错, 请稍后重试" ------  item服务有延迟, zuul超时-降级了## 9. ActuatorSpringBoot提供的一个项目监控工具, 提供项目的多种监控日志a. 监控日志:健康状态;spring容器中所有的对象;springmvc设置的所有路径;环境参数, 环境变量;虚拟机的堆内存;b. 实现:依赖: 间接依赖, zuul中有, yml: 暴露哪些监控日志m.e.w.e.i=* 暴露全部监控数据m.e.w.e.i=health,beans,mapping,hystrix.stream     management:endpoints:web:exposure:include: - health- beansc. 访问路径 --暴露的监控日志http://localhost:3001/actuator### java虚拟机内存分析MAT## 10. hystrix dashboard  链路监控Hystrix仪表盘: 监控Hystrix降级和熔断情况把一个服务的监控日志(actuator)以图表的形式展示a. Hystrix利用Actuator工具,暴露自己的监控日志,b. 搭建仪表盘:创建module: sp07-hystrix-dashboard依赖: hystrix-dashboardyml配置: 允许抓取的服务列表启动类注解:@EnableHystrixDashboard访问路径:localhost:4001/hystrix把路径放在 Hystrix Dashboard     http://localhost:3001/actuator/hystrix.stream可以是完全独立的项目, 不是在注册中心获取的服务## 11. 压力测试工具httpd-2.4.39-o102r-x86-vc14/Apache24/bin用 ab 工具,以并发50次,来发送20000个请求ab -n 20000 -c 50 http://localhost:3001/item-service/item/23/?token=123ab -n 20000 -c 100 http://localhost:3001/user-service/user/23## 12. Turbinehystrix 日志的聚合工具可以聚合多台服务器的Hystrix日志, Hystrix Dashboard 可以从 turbine 拉取 聚合之后的日志, 同时监控多台服务器实现:module: sp08-turbine依赖: eureka client, turbineyml:聚合的服务: zuul    localhost:3001 localhost:3002  从注册表获取给聚合的数据命名: defaultnew String("default")turbine:app-config: zuulcluster-name-expression: new String("default")启动类:@EnableTurbine访问:http://localhost:5001/turbine.stream## 13. 部署分布式服务  (多台主机)A. eureka                一台主机          172.18.6.73:2001B. zuul                  一台主机          172.18.6.74:3001C. dashboard,turbine     一台主机          172.18.6.75:4001/hystrix    172.18.6.75:5001/turbine.streamD. item 业务模块         所有主机E. hosts172.18.6.73 eureka1   172.18.6.73 eureka2F.访问 http://172.18.6.73:2001   注册表http://172.18.6.74:3001/item-server/item/23?token=sdf    访问item服务http://172.18.6.75:4001/hystrix  --填写-->  http://172.18.6.75:5001/turbine.stream    仪表盘## 14. vmware
> net 虚拟网络vmnet8 -> 子网ip 192.168.64.0> centos-8-2105阿里yum安装源/扩展源, python, pip, ansible, ip-static(配置固定ip)/ip-dhcp(自动获取ip){脚本文件-方便配置ip地址}已复制虚拟机登录: root root## 15. spring cloud config 配置中心  spring cloud config   放到   git仓库中/文件/数据库,  使用时拉取配置git仓库 --github,gitee,gitlab,csdn的chinacodea.配置文件:文件夹: config  文件: 服务2,3,4的application文件名: item-service-dev.yml   user-service-dev.yml    order-service-dev.yml b.git仓库:https://gitee.com/zhaoqing_lj/msapro2104.git配置用户名/密码:qingjing20140614@163.com   997z185q123f1fgfd8fdsf1fds5路径: msapro2104/springcloud1/config端口:java -jar i.jar --server.port=8002.ymlspring.cloud.config.override-none: true    远程下载配置 不会 覆盖本地配置c.配置中心仓库的地址存放配置文件的文件夹D. 搭建配置中心module: sp09-config依赖: eureka client, config serveryml:git仓库地址:存放配置文件文件夹:spring:application:name: config-servercloud:config:server:git:uri: https://gitee.com/zhaoqing_lj/msapro2104.gitsearch-paths: springcloud1/configusername: qingjing20140614@163.compassword: zq1815启动类注解:@EnableConfigServer访问:http://localhost:6001/item-service-dev.ymlhttp://localhost:6001/item-service/dev服务注册到eureka, 目的服务配置需要放到git的服务 要从eureka中获取配置中心服务, 再从配置中心服务中获取远程配置 到自己的服务E. 2,3,4 服务 从配置中心获取 配置信息依赖: spring-cloud-starter-configyml:  bootstrap.yml. 连接eureka. 指定配置中心 服务id. 指定下载的配置文件eureka:client:service-url:defaultZone: http://eureka1:2001/eurekaspring:cloud:config:discovery:enabled: trueservice-id: config-servername: user-serviceprofile: dev### 16. MQ 自动刷新配置nacos, 更改配置后, 后端服务自动刷新配置springcloudconfig, 需要MQ, 通过消息给服务 刷新配置更改配置后, 配置中心发送消息要求服务器更新配置信息,   配置中心把消息发送给MQ,  MQ再把消息给各个服务 服务刷新配置RabbitMQ 添加到 springcloud中A.Bus 辅助完成配置刷新指令的收发操作B.业务服务, 配置中心添加 Bus 组件 RabbitMQ-apia. 依赖: Bus, Binder-rabbit, spring-boot-starter-amqp, spring-rabbit-testb. yml:配合rabbitmq连接信息 spring:rabbitmq:host: 192.168.64.140port: 5672username: adminpassword: adminC.配置中心暴露刷新 端点a. 依赖: actuator(已有)b. yml:暴露刷新端点   management:endpoints:web:exposure:include: bus-refreshD.访问Bus刷新所有服务post --->   http://localhost:6001/actuator/bus-refresh    --->   Bus发送消息给RabbitMQ, 刷新配置, 业务服务重新连接了配置中心拉取了配置只刷新item-servicepost --->   http://localhost:6001/actuator/bus-refresh/item-serviceE.修改配置, 服务自动刷新配置使用User服务, 添加用户注入到userJson   a. 注解: @RefreshScope  // 需要注入(@Value()) 的业务层 添加注解  // 配置刷新到新的用户配置, 可以重新注入到对象中b. 使用Bus( post --->   http://localhost:6001/actuator/bus-refresh/user-item )  刷新业务配置-使业务重新在配置中心拉取配置刷新配置, 从配置中心拉取了配置,  (不是重启了服务)### 17. Bus 工具/组件 消息总线发送消息组件# 三. RabbitMQ 传递消息
## 1. 消息服务器 / 消息队列 Message Queue / 消息中间件 Broker## 2. 市场上的消息服务器 RabbitMQ, RocketMQ(阿里事务消息), TubeMQ(腾讯万亿级别), Kafka, ActiveMQ,## 3. Docker环境A. 克隆centos-8-2105  docker-baseB. 设置ip./ip-dhcp   ifconfigC. Mobaxterm连接服务器D. Docker在线/离线安装E. 安装DockerF. 克隆docker-base   rabbitmq设置ip  ./ip-static    ip:192.168.64.140## 4. 搭建RabbitMQ服务器    docker运行A. RabbitMQ镜像在线   docker pull rabbitmq:management   离线   docker load -i rabbit-image.gzB. docker防火墙:systemctl stop firewalld / disable重启docker:systemctl restart dockerC. 从镜像启动RibbitMQ  --在线拉取的新版本 3.9 以上 配置文件: mkdir /etc/rabbitmq  vim /etc/rabbitmq/rabbitmq.conf  default_user = admin default_pass = admin  运行:docker run -d --name rabbit -p 5672:5672 -p 15672:15672 \-v /root/msapro/rabbitmq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf \-e RABBITMQ_CONFIG_FILE=/etc/rabbitmq/rabbitmq.conf rabbitmq:management## 5. RabbitMQ 六种模式简单模式工作模式发布订阅模式路由模式主题模式RPC模式## 6. RabbitMQ使用场景A.服务与服务之间  解耦服务之间互相调用           直接调用   耦合高服务之间 插入rabbitmq服务  间接调用   降低耦合服务A  -> rabbitmq服务  {服务B, 服务C, 服务D, 服务E}  增加减少只需要从rabbitmq获取消息就行B.流量削锋大量的请求 -> rabbitmq服务器 -> 数据库rabbitmq 暂时缓存数据   原来: 并发的请求数据库     rabbitmq: 没有并发,一条一条处理C.异步调用服务器A(a,b,c,d) 请求 服务器BA把a 发给rabbitmq rabbitmq给B, A可以继续执行b,c..下面的业务## 7. 搭建maven项目A.依赖: amqp-client(com.rabbitmq)B.消息消息发送成功 channel.basicPublish()http://192.168.64.140:15672/ 获取到消息队列中的消息消息接收成功 channel.basicConsume()http://192.168.64.140:15672/ 消息队列中 就是空了取走了消息就没有了, C.模式https://gitee.com/zhaoqing_lj/msapro2104/tree/master/rabbitmq/rabbitmq-api/src/main/java/rabbitmq简单模式 : m11.连接 ConnectionFactory factory = new ConnectionFactory();factory.setHost("192.168.64.140");  factory.newConnection()  connection.createChannel(); 2.创建 helloWorld 队列         channel.queueDeclare("helloWorld",false,false,false,null);3.向 helloWorld 队列发生消息           channel.basicPublish("","helloWorld",null,in.getBytes());工作模式 : m2多个消费者, 轮循接收, 负载均衡提高效率发布订阅模式/群发模式 : m3交换机 fanout发送给所有 consumer 每个consumer收到所有消息,    使用交换机,fanout 扇形发布rabbitmq 交换机 ( Direct Fanout Topic )   路由模式 : m4交换机 direct, 绑定键, 给拥有绑定键的队列发送消息, 路由关键词:匹配    producer -routingKeyOne-> exchanges     consumer -routingKeyTwo-> exchanges发送消息+routingKeyOne     当routingKeyTwo=routingKeyOne时的consumer才能接收到消息主题模式 : m5交换机 Topic关键词  (和路由一样)关键词有特殊规则, aa.bb.cc.dd   *.*.cc.dd   aa.#D.消息合理分发a. 手动 Ack -> 手动回执接收消息 参数 第二个 false channel.basicConsume(Common.name,false,deliverCallback,cancelCallback);Ack中手动回执  回执位置 message{ envelope{ tag-int } }channel.basicAck(message.getEnvelope().getDeliveryTag(),false);b. 手动 qos (只在手动Ack时有效) 预抓取channel.basicQos(1);  --接收消息前    --每次接收一条,处理完之前不接受下一条E.回滚消息当接收消息服务 Consumer 宕机/停机 时, 消息会回滚到RabbitMQ服务器 内存F.消息持久化队列持久化,channel.queueDeclare(name,true,false,false,null);   第二个参数 持久队列消息持久化发送消息, 添加持久参数channel.basicPublish("",Common.name, MessageProperties.PERSISTENT_TEXT_PLAIN,s.getBytes());G.方法new ConnectionFactory();        --RabbitMQ的工厂连接 (com.rabbitmq.client.ConnectionFactory;)factory.newConnection();        --从工厂获取一个连接connection.createChannel();     --创建通信的通道创建队列channel.queueDeclare(queueName,durable,exclusive,autoDelete,arguments)          --队列声明创建交换机channel.exchangeDeclare(exchangesName, BuiltinExchangeType.FANOUT-交换机类型);         --交换机声明向队列发消息channel.basicPublish(exchange,routingkey,props,body-消息内容);         --基础发布接收消息channel.basicConsume(queueName,autoAck,deliverCallback-处理消息,cancelCallback-取消消息)          --基础消费手动qoschannel.basicQos(1);            --预抓取,每次接收一条,处理完之前不接受下一条绑定交换机channel.queueBind(queueName,exchangesName,routingKey);          --队列捆绑## 8. RabbitMQ使用案例A.Bus配置刷新指令  主题模式解耦,异步调用B.sleuth+zipkin联络跟踪简单模式解耦,流量削峰C.购物系统 产生订单 到数据库订单的流量削峰购物系统生成订单发送到 rabbitmq后台消费者 一个一个 顺序处理订单存储D.# 四. sleuth 在各个模块中产生链路跟踪日志A -> B -> C -> D     A, 4F5D6S7RE3SF4, 4F5D6S7RE3SF4, TRUE请求服务时产生id(A-id), A-id作为整条链路的id(说明是同一条链路,一次调用过程)TRUE(true把日志发送到zipkin,抽样10%发到zipkin)## 1. 添加sleuth依赖: spring-cloud-starter-sleuth配置: 自动配置## 2. 请求A.报500zuul 06 -> order 03 -> { user 04, item 02 }code: 500,msg: "后台服务出错, 请稍后重试"   item服务有延迟, zuul超时-降级了B.后台输出日志   sleuthINFO [zuul,c2013aea7e6c21aa,c2013aea7e6c21aa,true] # 五. sleuth + zipkin链路跟踪## 1. sleuth 产生的日志 发送给 zipkinA.直接连接zipkin, 提交数据紧耦合B.通过消息服务,发送日志a.解耦b.流量削峰## 2. 添加zipkin  客户端A.通过消息服务发送日志 需要RabbitMQB.依赖: zipkin客户端--spring-cloud-starter-zipkin, rabbitMQ--spring-boot-starter-amqpC.yml: 日志发送方式rabbitmq连接配置spring:rabbitmq:host: 192.168.64.140port: 5672username: adminpassword: adminzipkin:sender:type: rabbit## 3. zipkin服务A.下载服务https://github.com/openzipkin/zipkin   Quick-start -> latest released serverB.启动服务java -jar zipkin-server-2.23.2-exec.jar --zipkin.collector.rabbitmq.uri=amqp://admin:admin@192.168.64.140:5672C.访问http://localhost:9411/zipkin# 六. 拼多商城 购物系统 RabbitMQ购物系统产生大量订单   存储   到数据库使用 RabbitMQ 做流量削峰, 在rabbitmq中排队处理(缓存在rabbitmq中)## 1. 导入项目  pd-web   提交订单 saveOrderpom.xml -> make as mavenjdk1.8## 2. 导入数据库删除数据 pd_user, pd_order, pd_order_item## 3. 启动项目配置项目的启动配置 项目配置(configuration) -> working directory 设置到 pd-web 模块目录,然后重启项目或者  program arguments -> $%MODULE_WORKING_DIR%$## 4. 修改订单, 向 rabbitmq 发送订单数据    ------------------------------A.依赖: rabbitmq---spring-boot-starter-amqpB.yml: 连接rabbitmqC.创建 队列orderQueue 参数的封装对象, 在 启动类    创建    orderQueue,true,false,falseorg.springframework.amqp.core.Queue 包 封装队列自动配置类-RabbitAutoConfiguration 使用参数创建队列D.在OrderServiceImpl 注入spring提供的rabbintmq工具: AmqpTemplateE.amqpTemplate.convertAndSend() 发送订单转换并发送方法, order对象会自动转换成byte[]数组再 发送  --序列化F. 发送订单 到 购物车  支付-保存订单 到了 RabbitMQ## 5. 项目 pd-web-consumer   消费订单    ------------------------------------接收消息, 把订单存储到数据裤   类 OrderConsumerA. 注解: @RabbitListener(queue="orderQueue")通过注解配置, 接收消息@ComponentB. 处理消息的方法, @RabbitHandler,  具有这个注解的方法接收消息C. 调用业务方法完成订单存储Z. 总结接收消息 注解@RabbitListener(queues="orderQueue")  queues指定队列接收队列消息, 反序列化 成一个订单实例给方法参数@RabbitHandler 配合@RabbitListener注解, 指定处理消息的方法## 6. 订单   生成-用户支付   消费-订单保存到数据库            -----------------------------------由把订单保存到数据库      改变为     先把订单发消息给rabbitmq,然后消费者接收消息 ---------A.生成订单   (1)商品添加到购物车 (2)添加收货地址--原因:如果没有地址后端会判断报空指针异常  (3)用户支付订单-保存订单到RabbitMQB.保存订单(1)consumer 从RabbitMQ中获取到队列中的消息(2)执行service业务, 保存到数据库# 七. rabbitmq 整合 springboot依赖: spring-boot-starter-amqp, spring-rabbit-testyml: spring.rabbitmq.host port username password
## 1. 模式简单模式 : m1发送: amqpTemplate.convertAndSend("helloworld","Hello World ZhaoQing");  // 自动转换byte数组再转换接收: @RabbitListener(queues = "helloworld")  public void receive(String msg){  // 参数接收到注解传过来的参数     System.out.println("收到 : "+msg);    }main: 配置queue参数: @Bean return  new Queue("helloworld",false);  手动执行发送消息: 执行方法工作模式 : m2多个消费者, 轮循接收, 负载均衡提高效率合理分发: spring默认ack自动回执, qos=1 yml prefetch=1持久化: 队列 new Queue("task_queue",true);  消息 spring默认持久发布订阅模式/群发模式 : m3交换机 fanout    producer: amqpTemplate.convertAndSend("logs","",info); consumer:     @RabbitListener(bindings = @QueueBinding(value = @Queue,exchange = @Exchange(name = "logs",declare = "false")))main: 创建交换机, 执行send路由模式 : m4交换机 direct, 绑定键, 给拥有绑定键的队列发送消息,   : key主题模式 : m5交换机 Topic关键词  (和路由一样)关键词有特殊规则, aa.bb.cc.dd   *.*.cc.dd   aa.## 八. 数据库初始化工具/模块重置所有数据库表SpringBoot db-init
## 1. 新建依赖: jdbc api, mysql driveryml: 数据源datasourceresource:sql/ 1.sql,2.sql,3.sql,..启动来: 执行sql脚本-初始化数据库
## 2. jdbc 脚本执行器A.Spring 提供的    ScriptUtils.executeSqlScript()参数: 数据库的链接 java.sql.Connection , 文件资源对象B. 文件资源对象路径资源: new ClassPathResource(文件路径String, DatabaseInitApplication.class.getClassLoader());编码转换: new EncodedResource(classPathResource, "utf-8");# 九. 分布式事务 部署服务    案例 (无事务处理)    seata-at## 1. 数据库初始化## 2. eureka 注册中心搭建 8761 模块 eureka依赖: eureka serveryml: 禁用保护模式, 单台服务器(不注册,不拉去), 启动类注解: @EnableEurekaServer## 3. 父子项目父: order-parentTwopom.xml子: account  实现扣减账户金额, storage 减少库存, order 保存订单 调用s和c 依赖: 清空(都在父项目里)yml: app.name, port, eureka, datasource, mybatisp, loggingpojo, Dao, Service, Controller## 4. 全局唯一id发号器https://github.com/lookingatstarts/easyIdGenerator ,下载发号器项目依赖: eurekayml: eureka配置详情:两个算法easy-id-generator.snowflakeeasy-id-generator.segment   数据库方式db-list: seata_order     数据库列表,  使用配置文件seata_order.properties访问: http://localhost:9090/segment/ids/next_id?businessType=order_business## 5. Feign   远程调用order订单添加Feign,调用库存和账户服务a.调用发号器获得全局唯一idb.调用库存服务减少商品库存c.调用账户服务扣减用户金额A.依赖:spring-cloud-starter-openfeignB.yml配置超时时长: ribbon.ReadTimeout=10000C.注解@EnableFeignClientsD.声明式客户端接口@FeignClient(name="easy-id-generator") 描述接口(指定被调用服务名)@GetMapping("/segment/ids/next_id")   描述方法(执行被调用服务的方法)@FeignClient(name = "EASY-ID-GENERATOR")public interface EasyIdGeneratorClient {@GetMapping("/segment/ids/next_id")String nextId(@RequestParam String businessType);}# 十. 分布式事务  分布式事务: Seata  AT,   TCC,  SAGA,   XA,  可靠消息最终一致性(异步确保),   最大努力通知A B C 分布式服务    A -> B   A -> CB 发生事务  C 知道不了解决: 事务协调器## 1.Seata分布式事务框架提供高性能和简单易用的分布式事务服务支持: AT,  TCC,  SAGA,  XA# 十一. Seata AT## 1. Seata AT 基本原理### 1.1 事务协调器  Transaction CoordinatorA. 第一阶段: 执行各分支事务   @TransactionalB. 第二阶段:控制全局事务最终提交或回滚    ### 1.2 第一阶段
#### 1.2.1 事务管理器  Transaction Manager事务管理器 向 事务协调器 申请开启全局事务(产生XID)     TM 向 TC 申请开启全局事务, TC 产生全局事务id(XID)
#### 1.2.2 资源管理器 Resource Manager执行业务,  开启 资源管理器并把XID给它, 职责: 管理分支事务(本地事务), 与TC通信,上报分支事务的执行状态,接收全局事务的提交和回滚指令RM 向 TC 注册分支事务, 把分支事务纳入对应的全局事务管理分支事务执行成功, RM 发送事务状态给 TC, TC 将事务状态给TM### 1.3 第二阶段 提交全部分支事务执行完毕,  TM 收集了所有分支事务的 事务状态 -> 做做种决策, 让RM 发送提交指令完成提交操作### 1.4 事务协调器 第一阶段/第二阶段  执行流程总结TC 事务协调器         全局事务,分支事务TM 事务管理器         收集分支事务的事务状态, 决策全局事务提交/回滚RM 资源管理器         管理分支事务, 发送分支事务状态, 全局事务的提交/回滚指令/操作
#### 1.4.1 第一阶段a. TM 向 TC 申请开启全局事务, TC 产生 XID 并发给 TMb. 执行事务, 启动 RM 并把 XID 给 RM, RM 携带 XID 向 TC 注册分支事务c. 事务成功, RM 上报事务状态给 TC, TC 把事务状态发送给 TM,d. 执行其他事务, 注册分支事务, 最终 TM 手机所以分支事务的事务状态
#### 1.4.2 第二阶段a. TM 收集到所有分支事务的事务状态, 决策全局事务状态,b. TM 把全局事务状态发送给 TC c. TC 根据全局事务状态给 RM 发送指令, RM 执行 提交/回滚 指令/操作## 2. 具体工作机制
### 2.1 第一阶段库存表 库存 50 改为 40a. 把表中原来的数据取出来b. 进行修改操作c. 取出表中的新数据d. 把旧数据和新数据 合并, 存放到 事务回滚日志表e. 第一阶段完成, 将状态上报给 TC
### 2.2 第二阶段事务失败--回滚a. TC 发送回滚指令 给 RMb. 根据事务回滚日志表, 将库存表中的数据恢复c. 删除事务回滚日志, 完成回滚操作事务成功--提交a. TC 发送提交指令 给 RMb. 删除事务回滚日志, 完成第二阶段提交操作## 3.TM TC RMTC 全局协调     单独的服务TM 全局管理/存储事务状态日志      调用服务的服务--添加RM 分支事务     被调用服务--添加A->B    A->C    TC seata-server服务TM 在A中添加RM B,C中添加# 十二. 微服务添加 Seata AT 分布式事务
## 1. Seata Server - TC 全局事务协调器A. 下载 https://github.com/seata/seata/releasesB. 配置文件conf/registry.conf连接eureka注册中心conf/file.confseata server 运行时记录日志的数据库bin/seata-server.bat降低虚拟机内存大小(默认2G)C. 启动双击 seata-server.bat## 2. 业务中添加 Seata AT 事务A.依赖: seataB.配置:application.yml    --事务组的组名spring.cloud.alibaba.seata.tx-service-group=order_tx_groupregistry.conf      --注册中心地址                   新建type=eurekafile.conf          --事务组使用哪个协调器           新建vgroupMapping.order_tx_group(组名) = "seata-server"(协调器)    要使用的协调器 C.自动配置类创建数据源代理对象DSAutoConfiguration  @Configurationa. 注入数据源配置 yml中的datasource        @ConfigurationProperties(prefix = "spring.datasource")b. 数据源 @Beannew HikariDataSource();   hikari的url是jdbcUrl(修改yml添加jdbcUrl,datasource下jdbcUrl: ${spring.datasource.url})c. 数据源代理 @Beannew DataSourceProxy(dataSource);d. 指定注入spring哪个数据源对象@Primary  首选对象数据源配置类@Configurationpublic class DSAutoConfiguration {注入数据源配置 yml中的datasource@ConfigurationProperties(prefix = "spring.datasource")数据源指定连接池 new HikariDataSource();@Beanpublic DataSource dataSource(){return new HikariDataSource();}数据源代理@Primary@Beanpublic DataSource dataSourceProxy(DataSource dataSource){return new DataSourceProxy(dataSource);}}e. 排除spring默认数据源自动配置类,使用自己的 DSAutoConfiguration@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)D.业务方法注解@Transactional  控制本地事务@GlobalTransactionsl   启动全局事务  seata提供业务模块创建TM 向TC 申请开启全局事务, TC 向 TM 发送 XID第一个模块中添加a. 本地事务注解 @Transactional   全局事务注解 @GlobalTransactional添加到 调用其他服务的服务 方法上@Transactional@GlobalTransactionalpublic void create(Order order) {}  // 创建订单order 调用 account账户 和 storage库存E.被调用服务添加 Seata AT依赖 seata配置文件  application.yml  registry.conf  file.conf自动配置类数据源代理 DSAutoConfiguration启动类注解@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)业务方法注解@Transactional 本地事务# 十三. 分布式事务  TCCone. 每个阶段的数据操作要自己进行编码, 事务框架无法自动处理two. 效率高, 不对数据加全局锁, 允许多个事务同时操作数据
## 1. 基本原理A.第一阶段   Try --预留资源, 冻结数据例如: 先把要扣减的金额预留(冻结)出来    --要处理的数据我先拿出来放起来,执行完我再处理数据B.第二阶段   Confirm --确认/提交, 使用上一阶段预留的数据, 完成业务数据处理Cancel  --取消/回滚, 对第一阶段预留的数据, 再回复为原始数据# 十四. 微服务添加 Seata TCC 分布式事务
## 1.使用Seata server## 2.添加TCC事务A.依赖:seataB.配置文件application.ymlregistry.conffile.confC.事务自己实现   不像at事务自动配置D.Mapper添加新的数据库操作Try --冻结数据   update向表中插入数据状态不可见Confirm --确认提交Cancel --取消,回滚E.按照seata定义的规则, 添加  TccAction接口添加TCC三个操作的方法,调用mapper的三个数据库操作F.业务方法中, 手动调用第一阶段方法全局事务 @GlobalTransactionalD E F  步骤自己写代码执行冻结, 配置冻结操作的代码, 业务调用冻结方法G.第二阶段不需要手动执行@GolbalTransactional 全局事务  --在调用服务的服务上添加 一次, 被调用服务不需要添加二阶段就会自动执行## 3.TCC 基本原理的实现(需要自己写代码实现)A.对数据库的操作, 具体业务代码, OrderMapper.xml中sqlB.OrderTccAction接口,   两个阶段要实现的业务方法prepare()commit()rollback()C.接口实现类prepare()  执行   创建订单操作create()commit()   执行   更新订单状态操作 updateStatus()rollback() 执行   删除订单操作 deleteById()D.业务执行prepare()方法 --TCC的Try阶段E.问题 ???第一阶段:  手动执行了 prepare()第二阶段:  commit() 和 rollback() 怎么调用的解决: @GlobalTransactional create() 方法上两个阶段业务注解@TwoPhaseBusinessAction(name = "OrderTccAction",commitMethod = "commit",rollbackMethod = "rollback")F.幂等性控制防止重复提交/回滚官方案例,赋值粘贴## 4.幂等性控制如果重复执行提交或回滚,    就执行一次,结果一样理解: 防止重复提交回滚,    重复执行,不执行二阶段解决: 使用标记, 二阶段判断有没有标记,没有标记就是执行完了ResultHolder# 十五. RocketMQ  消息高可用  安装不使用 docker 运行, 直接在linux中运行## 1. 搭建rocketmq服务jdk, jdk环境变量rocketmq文件, rocketmq环境变量, rocketmq减小服务(name-server,broker)内存, 启动A.需要的资源: jdk1.8, rocketmq-all-4.7.0-bin-release, rocketmq-console-ng-1.0.1B.jdk1.8tar -xf jdk-8u212-linux-x64.tar.gz -C /usr/local/   解压vim /etc/profile                              jdk 配置文件修改, 在/usr/local下# 在文件末尾添加以下内容:export JAVA_HOME=/usr/local/jdk1.8.0_212export PATH=$JAVA_HOME/bin:$PATHsource /etc/profile                             使环境变量生效C.rocketmq 二进制文件a.下载 wget https://mirror.bit.edu.cn/apache/rocketmq/4.7.0/rocketmq-all-4.7.0-bin-release.zip b.解压缩unzip rocketmq-all-4.7.0-bin-release.zip -d /usr/local/# 修改一下文件夹名,改成 rocketmq 方便使用mv /usr/local/rocketmq-all-4.7.0-bin-release /usr/local/rocketmqc.配置环境变量 ROCKETMQ_HOME 和 PATHcd /usr/lcoalvim /etc/profile# 在文件末尾添加以下内容:export ROCKETMQ_HOME=/usr/local/rocketmqexport PATH=$ROCKETMQ_HOME/bin:$PATHd.让环境变量立即生效source /etc/profilee.减小rocketqm使用的内存cd /usr/local/rocketmq/修改 name server 内存改为 256m# 编辑 bin/runserver.shvim bin/runserver.sh# 找到文件中下面这一行:JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"# 将 -Xms4g -Xmx4g -Xmn2g 修改为 -Xms256m -Xmx256m -Xmn128mJAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"修改 broker 内存改为 256m# 编辑 bin/runbroker.shvim bin/runbroker.sh# 找到文件中下面这一行:JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"# 将 -Xms8g -Xmx8g -Xmn4g 修改为 -Xms256m -Xmx256m -Xmn128mJAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"f.启动rocketmq先启动 name server# 进入 rocketmq 目录cd /usr/local/rocketmq/# 启动 name servernohup sh bin/mqnamesrv &# 查看运行日志, 看到"The Name Server boot success."表示启动成功tail -f ~/logs/rocketmqlogs/namesrv.log再启动 broker# 启动 broker, 连接name server: localhost:9876nohup sh bin/mqbroker -n localhost:9876 &# 查看运行日志, 看到"The broker[......:10911] boot success."表示启动成功tail -f ~/logs/rocketmqlogs/broker.log g.关闭防火墙rocketmq的通信会用到多个端口, 为了方便测试我们关闭防火墙# 关闭防火墙systemctl stop firewalld.service# 禁止防火墙开机启动systemctl disable firewalld.serviceh.测试# 通过环境变量, 告诉客户端程序name server的地址export NAMESRV_ADDR=localhost:9876/usr/local/rocketmq# 启动生产者来测试发送消息sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer# 启动消费者来测试接收消息sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumeri.rocketmq命令关闭 brokermqshutdown broker关闭 nameservermqshutdown namesrvj.收发消息出现超时问题cd /usr/local/rocketmq/vim conf/broker.conf末尾添加brokerIP1=192.168.64.141关闭 broker 服务mqshutdown broker重新使用 broker.conf 配置启动 brokernohup sh bin/mqbroker -n localhost:9876 -c conf/broker.conf &D.进程查看是否运行jps## 2. rocketmq注册中心,消息服务name server --rocketmq的注册中心内存 4Gbroker      --消息服务,消息中间件内存 8G## 3.管理界面在开源项目 rocketmq-externals 中提供了rocketmq 的管理界面: 地址为: https://github.com/apache/rocketmq-externalsgithub 在国内访问缓慢, 也可以使用码云的镜像项目, 地址为: https://gitee.com/mirrors/RocketMQ-ExternalsA.克隆项目cd /usr/local/rocketmq/# 克隆 rocketmq-externals 项目git clone https://gitee.com/mirrors/RocketMQ-ExternalsB.maven打包yum install -y maven# 进入管理界面项目的文件夹cd RocketMQ-Externals/rocketmq-console# 执行maven 打包命令, 执行时间较长, 请耐心等待mvn clean package -Dmaven.test.skip=trueC.运行启动# 运行管理界面nohup java -jar rocketmq-console-ng-1.0.1.jar --server.port=8080 --rocketmq.config.namesrvAddr=localhost:9876 & D.访问http://192.168.64.141:8080# 十六. rocketmq
## yi. 双主双从 同步赋值集群方案## er. 基本原理Topic  集群服务器A.生产者负载均衡轮循B.消费者负载均衡AllocateMessageQueueAveragely 平均分配             11,22,33AllocateMessageQueueAveragelyByCircle 环形分配     1,2,3,1,2,3## san. rocketmq 原生 API
### 0.module依赖: rocketmq-store, rocketmq-client
### 1.同步消息A.主从复制: 生发消息, 向消复制, 消返回给生B.生产者* 创建生产者, 设置 name server     ---new DefaultMQProducer("producer1")* 连接服务器, 启动, (从注册表中的地址连接消费者)    ---producer1.setNamesrvAddr("192.168.64.141:9876"); producer1.start();* 消息封装 Message    ---new Message("Topic1","Tag1",str.getBytes());*      Topic  --相当于一级分类     Tag    --相当于二级分类* 发送消息  ---producer1.send(message);*      返回结果 [topic=Topic1(目录), brokerName=localhost.localdomain, queueId=3(消息序列id)], queueOffset=0(消息下标)]C.消费者* 创建消费者   ---new DefaultMQPushConsumer("consumer1");* 设置name server   ---consumer1.setNamesrvAddr("192.168.64.141:9876");* 从哪里订阅消息   ---consumer1.subscribe("Topic1","Tag1");     Tag1 或 * 或 Tag1 || Tag2 || Tag3* 处理消息的监听器   ---consumer1.setMessageListener(new MessageListenerConcurrently(){}--启动多个线程, 并发的处理消息)*      new MessageListenerConcurrently() {public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {*                 for (MessageExt messageExt : list) {*                     String s = new String(messageExt.getBody());*                     System.out.println("收到"+s);*                 }*                 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;  // 成功* //                return ConsumeConcurrentlyStatus.RECONSUME_LATER; // 稍后会收到*             }* 启动消费者   ---consumer1.start();D.计时消息--延时消息判断消息时间### 2.异步消息主从复制: 生发消息, 向消复制,同时返回给自己,    生产者消费者
### 3.单向消息生产者消费者
### 4.顺序消息A.消费者接收消息的顺序问题: 发送时,放到队列中(轮循放), 多个队列(存放位置),多个线程(处理的快慢)   (rocketmq 一个队列由一个消费者接收消息)    消费者接收到的消息 顺序就乱了解决: 把消息发送到一个队列 且 消费者由一个线程处理B.生产者   ---发送消息到同一个 消息序列* 设置队列选择器* producer2.send(message, new MessageQueueSelector() {}, orderId);  // 参数: message-给Selector->message, 队列选择器, 选择依据-给Selector->object* new MessageQueueSelector() {public MessageQueue select(List<MessageQueue> list, Message message, Object o) {  * // 参数: 服务器端队列列表, 正要发送的消息, 队列选择依据*   Long orderId = (Long) o;  int index = (int) (orderId % list.size());  return list.get(index); }C.消费者   ---单线程接收消息* 设置监听器(单线程)*      consumer2.setMessageListener(new MessageListenerOrderly() {}) //MessageListenerOrderly()启动的是一个单线程* new MessageListenerOrderly() {public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {*    for (MessageExt messageExt : list) {System.out.println("收到"+new String(messageExt.getBody()));}*    return ConsumeOrderlyStatus.SUCCESS;}
### 5.延时消息A.生产者发送消息之前, 进行延时,  一段时间后消费者才能收到消息B.时间级别this.messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";生产者   ---message.setDelayTimeLevel(3);消费者
### 6.批量消息生产者消费者
### 7.消息过滤Tag 过滤对自定义属性过滤生产者消费者
### 8.事务消息  高可靠消息A.异步调用, 两个模块之间实现异步调用事务消息的原理发送者: 1.发送本消息(不会给消费者) 2.执行本地事务 3.提交消息消费者: 接收消息不允许失败, 失败会一直重试18次, 最后不行成为死消息-人工处理发送者: 1.发送本消息(不会给消费者) 2.执行本地事务 3.提交消息* 创建事务消息产生者, 设置nameserver*      ---new TransactionMQProducer("producer3");*      * 设置事务消息监听器 --执行本地事务, 处理服务器的回查*      ---producer3.setTransactionListener(new TransactionListener() {})* new TransactionListener() {*   @Override // 执行本地事务*   public LocalTransactionState executeLocalTransaction(Message message, Object o) {*   System.out.println("执行本地事务, 参数: "+message);*   if (Math.random()<0.5){System.out.println("本地事务执行成功"); return LocalTransactionState.COMMIT_MESSAGE;*   }else {System.out.println("本地事务执行失败");return LocalTransactionState.ROLLBACK_MESSAGE;}}**    @Override  // 回查*    public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {*    System.out.println("处理服务器网络中断");return LocalTransactionState.UNKNOW;}}*    * 启动* 发送事务消息, 会触发监听器来执行本地事务*      ---  producer3.sendMessageInTransaction(message,"执行本地事务的参数数据");*消费者: 接收消息不允许失败, 失败会一直重试18次, 最后不行成为死消息-人工处理System.out.println("处理消息成功");return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;System.out.println("处理消息失败");return ConsumeConcurrentlyStatus.RECONSUME_LATER;# 十七. spirng boot 订单案例 整合 rockermq
## 1. model依赖: rocketmqrocketmq-spring-boot-starter yml: name server, 生产者组组名rocketmq:name-server: 192.168.64.141:9876producer:group: order-producer数据库表: tx_table 记录事务执行的状态业务: TxInfo, TxMapper  --insert, select  记录事务执行状态,应对回查message: 封装消息数据的 AccountMeaage对象工具: 添加JsonUtil工具, 处理消息数据的格式转换业务代码: 先执行发送消息, 再执行订单业务create(Order order){rocketMQTemplate.sendMessageInTransaction("order-topic", msg, order); }监听器: 执行本地事务(存储订单), 事务状态回查#https://blog.csdn.net/weixin_38305440/article/details/108609574?spm=1001.2014.3001.5502# 零. 知识点
## application.yml中的 profilespringboot项目中的一小段配置, 可选择是否使用主配置: 提取配置共性profile: 相同配置属性,不同属性值
> application.ymlserver:port: 8001# 项目使用 prof1# yml中 主配置和prof1配置合并使用spring:profiles:active: prof1# profile配置# 启动项目时加载profile  java -jar a.jar --spring.profiles.active=prof1--- (三个行线之间写profile配置)spring:profiles: prof1eureka:instance:hostname: eurekaclient:register-with-eureka: true  #profile的配置会覆盖公用配置fetch-registry: true        #profile的配置会覆盖公用配置service-url:defaultZone: http://eureka1:2001/eureka  #eureka启动时向eureka1注册---> profile 配置名dev, test, prod, ## 上下文对象  ContextSpring Context, Spring 上下文对象, 对象池创建的所有对象, 实例程序中 通用/共用 资源 (各个组件中要使用的数据)## bootstartp.yml 和 application.ymlbootstrap.yml     引导配置  application.yml   应用配置优先级:   bootstrap.yml > application.yml > tomcat服务 > 

msapro-note相关推荐

  1. Paddle Release Note

    Paddle Release Note 重要更新 飞桨paddle框架2.0.0版本有如下重要更新: • 编程范式:默认开启动态图模式进行模型开发和训练,通过动转静的方式进行模型部署和训练加速.如果需 ...

  2. 机器学习与高维信息检索 - Note 7 - 核主成分分析(Kernel Principal Component Analysis,K-PCA)

    Note 7 - 核主成分分析(Kernel Principal Component Analysis) 核主成分分析 Note 7 - 核主成分分析(Kernel Principal Compone ...

  3. 机器学习与高维信息检索 - Note 6 - 核, 核方法与核函数(Kernels and the Kernel Trick)

    Note 6 核, 核方法与核函数 到目前为止,我们所讨论的机器学习算法的成功都依赖于对输入数据分布的假设.例如,PCA的效果越好,数据围绕线性子空间分布.或者在线性判别分析中,我们假设类的高斯分布, ...

  4. ADPRL - 近似动态规划和强化学习 - Note 10 - 蒙特卡洛法和时序差分学习及其实例 (Monte Carlo and Temporal Difference)

    Note 10 蒙特卡洛法和时序差分学习 Monte Carlo and Temporal Difference 蒙特卡洛法和时序差分学习 Note 10 蒙特卡洛法和时序差分学习 Monte Car ...

  5. 机器学习与高维信息检索 - Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及基于CVXOPT的相关实例

    Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及相关实例 5.1 FNN的定义和动机 粗略地说,前馈神经网络(FNN)是一种特殊的函数类 ...

  6. ADPRL - 近似动态规划和强化学习 - Note 8 - 近似策略迭代 (Approximate Policy Iteration)

    Note 8 近似策略迭代 Approximate Policy Iteration 近似策略迭代 Note 8 近似策略迭代 Approximate Policy Iteration 8.1 通用框 ...

  7. 机器学习与高维信息检索 - Note 4 - 主成分分析及其现代解释(Principal Component Analysis, PCA)及相关实例

    主成分分析及其现代解释 4. 主成分分析及其现代解释 Principal Component Analysis and Its Modern Interpretations 4.1 几何学解释 The ...

  8. ADPRL - 近似动态规划和强化学习 - Note 7 - Approximate Dynamic Programming

    Note 7 - 近似动态规划 Approximate Dynamic Programming 7. 近似动态规划 (Approximate Dynamic Programming) 7.1 近似架构 ...

  9. ADPRL - 近似动态规划和强化学习 - Note 6 - Mitigating the Curse of Dimensionality

    Note 6 Mitigating the Curse of Dimensionality 减轻维度诅咒 6. Mitigating the Curse of Dimensionality 减轻维度诅 ...

  10. ADPRL - 近似动态规划和强化学习 - Note 4 - Policy Iteration Algorithms

    Note 4 - Policy Iteration Algorithms 4. Policy Iteration Algorithms 补充:范数的性质 4.1 贪婪诱导策略的特性 (Properti ...

最新文章

  1. 鸡肋的PHP单例模式
  2. java biginteger使用_java中的BigInteger的基本用法 | 学步园
  3. 你真的了解Scrum吗?
  4. LeetCode 117. Populating Next Right Pointers in Each Node II
  5. 无监督学习和半监督学习
  6. [置顶] 总结工作中常用到的linux命令
  7. 《c语言从入门到精通》看书笔记——第15章 存储管理
  8. O2O概念实践案例: Giftly改变送礼方式
  9. ofo悄然搬离中关村,联合创始人出走,千万用户的押金还能退回来吗?
  10. scrapy_redis项目配置
  11. 决策树Decision Tree+ID3+C4.5算法实战
  12. 【优化预测】基于matlab遗传算法优化RBF神经网络预测【含Matlab源码 451期】
  13. pointofix 全局快捷键_屏幕画笔(Pointofix)
  14. 数学建模——sas(1)——几种统计方法
  15. 使用Python2.7和火狐浏览器下载QQ空间好友相册
  16. ntp子母钟(gps子母钟系统)时钟系统在智能交通系统中的重要性
  17. 基于CANoe的ECU Bootloader刷写软件
  18. QT界面优化---反走样
  19. 苹果app一键签名工具开发者专用版 (iOS签名工具,苹果签名工具。ipa签名工具)
  20. Matlab中的冲激函数

热门文章

  1. 有感于董洁为子找幼儿园因不是外籍被拒 怪自己“不争气”
  2. 需要细读的好文章(搜集)
  3. 宇视摄像机网页界面登录“提示加载插件失败,点击下载安装最新插件”
  4. 关于正负数比较大小的问题
  5. 21 个 MySQL 表设计的经验准则
  6. jQuery思维导图
  7. C语言的/t到底有什么用
  8. 微信小游戏Banner广告
  9. 毕业设计| 单片机自动分拣小车(上货/卸货/WIFI识别)
  10. 测绘资质办理需要注意的流程和规定