spring cloud

MQ(mybatis-plus)

有三个重要注解

@TableName

@TableId

@TableField :成员变量与字段名不一致,且是is开头,如ismarried在数据库里是is_married则需要是由该注解  

iservice批处理

在yml配置中的连接mysql的配置的url中加上开启rewriteBatchedStatements=true参数,配置jdbc参数,批处理默认是关闭的,由mybatis管控。

代码生成器:

iservice中DB的静态方法

可以解决循环依赖,注入问题,但要考虑MP的版本问题,版本低的

 增删改查:

查:List,select,

删:delete,remove

增:save,insert

MP提供的逻辑删除配置

枚举处理器:

用于解决数据库中不同数字对应的状态的简易处理操作。

实现枚举类型变量与数据库类型字段的转换步骤:

1.将数据库中的字段用枚举封装起来。

@Getter//使用该注解,方便我们去取值
public enum UserStatus {
    NORMAL(1,"正常"),
    FROZEN(2,"冻结"),
    ;
    @EnumValue
    //加上该注解后,数据库知道该值往数据库中写
    @JsonValue
    //返回的值是1或2
    private final int value;
    private final String desc;

    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

2,在配置文件中配置同一的枚举处理器,实现类型转换。 

json处理器   

Docker:

Docker部署数据库mysql:

在finalshell中:

如果要root管理员权限的话:输入us  回车

在输入虚拟环境的密码,即可。

部署MySQL
先停掉虚拟机中的MySQL,确保你的虚拟机已经安装Docker,且网络开通的情况下,执行下面命令即可安装MySQL:

在finalshell中先:

然后创建一个通用网络:

docker network create hm-net

 使用下面的命令来安装MySQL:

docker run

-d \ --name mysql \

-p 3306:3306 \

-e TZ=Asia/Shanghai \

-e MYSQL_ROOT_PASSWORD=123 \

-v /root/mysql/data:/var/lib/mysql \

-v /root/mysql/conf:/etc/mysql/conf.d \

-v /root/mysql/init:/docker-entrypoint-initdb.d \

--network hm-net\

mysql

注意docker run:创建并运行一个容器,-d是让容器在后台运行

docker run:创建并运行一个容器,-d是让容器在后台运行
-name mysql:给容器起个名字,必须唯一
-p3306:3306:设置端口映射
-eKEY=VALUE:是设置环境变量

注意:mysql是镜像名,并且正确的写法是,镜像名:版本号,如果不写版本号,默认是最新的版本
 

此时,通过命令查看mysql容器:

docker ps

设置mysql开机自启: 

docker update --restart=always mysql(容器名,也可以是容器id)

镜像仓库:

存储和管理镜像的平台,Docker'官方维护了一个公共仓库:Docker Hub。
在finallshell中输入 docker inspect mysql 查询MySQL内置的IP地址(电脑终端不允许访问)


 docker pull:将远程镜像下载到本地镜像

docker images 查看本地镜像

docker rmi删除本地镜像

docker run运行docker

拉取nginx为例

容器内:

docker stop将正在运行的进程停掉

docker start 将停止的进程开启

docker ps 查看容器中运行中的镜像,

docker ps -a 查看容器内所有的镜像

docker  rm 删除的是容器

docker logs 查看运行的日志

docker exec 进入容器的内部

docker logs -f nginx:日志一直进行下去(若没加-f则不会一直生成日志)

 docker exec -it nginx bash进入nginx容器内部

exit退出容器

进入mysql容器(上面有)后

mysql客户端命令:

mysql -uroot -p
 

非强制删除(前提是要将容器停掉)

docker rm mysql 
 

强制删除:(不管是否在运行)

docker rm mysql -f

默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启:

# Docker开机自启

systemctl enable docker

# Docker容器开机自启

docker update --restart=always [容器名/容器id]

我们以Nginx为例给大家演示上述命令。

# 第1步,去DockerHub查看nginx镜像仓库及相关信息

# 第2步,拉取Nginx镜像

docker pull nginx

# 第3步,查看镜像

docker images

# 结果如下:

REPOSITORY TAG IMAGE ID CREATED SIZE

nginx latest 605c77e624dd 16 months ago 141MB

mysql latest 3218b38490ce 17 months ago 516MB

# 第4步,创建并允许Nginx容器

docker run -d --name nginx -p 80:80 nginx

# 第5步,查看运行中容器

docker ps

# 也可以加格式化方式访问,格式会更加清爽

docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第6步,访问网页,

地址:http://虚拟机地址

# 第7步,停止容器

docker stop nginx

# 第8步,查看所有容器

docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第9步,再次启动nginx容器

docker start nginx

# 第10步,再次查看容器

docker ps -format"table{{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第11步,查看容器详细信息

docker inspect nginx

# 第12步,进入容器,查看容器内目录

docker exec -it nginx bash

# 或者,可以进入MySQL

docker exec -it mysql mysql -uroot -p

# 第13步,删除容器

docker rm nginx

# 发现无法删除,因为容器运行中,强制删除容器

docker rm -f nginx

电脑开机让停止运行的docker运行起来: 

如何解决开机启动docker出现

“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the d”

的问题

检查 Docker 是否正在运行

首先,我们需要检查 Docker 是否正在运行。可以通过以下命令来检查 Docker 服务的状态:

登录后复制

systemctl status docker

如果 Docker 正在运行,你会看到类似下面的输出:

docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2021-01-01 00:00:00 UTC; 1h ago Docs: Main PID: 12345 (dockerd) Tasks: 27 CGroup: /system.slice/docker.service └─12345 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock 

相反,你会发现里面出现:

 Active: inactive (dead) 

启动docker:

sudo systemctl start docker

数据卷挂载:

前提是nginx正在运行:进入nginx

docker exec -it nginx bash
 

进入html目录,(cd和/之间有空格) 

cd /usr/share/nginx/html

进入成功之后显示

root@c1e01e4d2d8a:/usr/share/nginx/html# 
 

数据卷基本命令: 

查看volume的一些基础命令,和作用。 

 docker volume --help 

在执行docker runi命令时,使用-v数据卷:容器内目录可以完成数据卷挂载
当创建容器时,如果挂载了数据卷且数据卷不存在,会自动创建数据卷

创建一个数据卷,名字为html

docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx

查询卷内详细信息: 

进入卷内:

 docker volume inspect html        

查看详细信息: 

 ll

修改html内容:(也可以在MobaXterm中更方便修改)

vi  index.html

自定义镜像:

部署一个Java应用的步骤:


准备一个Linux服务器
安装JRE并配置环境变量
拷贝jar包
运行jar包

Dockerfile:

就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile帮我们构建镜像。常见指令如下:
 


 

 

容器网络连接: 

查询网卡:

ip addr

查看网络:  

docker network ls

一旦两个容器在同一网桥中,另一个容器可以通过ping容器名直接访问

网桥为hm-net

使nginx进入hm-net网桥

docker network connect hm-net nginx

查询容器网络连接情况 

docker inspect nginx 

docker compose:

其命令格式如下:

 在MobaXterm中

先su输入密码

后再

cd~

删除root目录中的mysql文件

rm -r -f mysql

到达根目录root,将wzx198012目录中的mysql文件复制到root下

 cp -r /home/wzx198012/mysql mysql

在mysql目录中创建data文件夹

mkdir data

 然后再创建mysql容器

微服务:

目前以灰色的版本为主

什么时候拆分微服务?
初创型公司或项目尽量采用单体项目,快速试错。随着项目发展到达
一定规模再做拆分
如何拆分微服务?
目标:高内聚、低耦合。
方式:纵向拆分、横向拆分
拆分后碰到的第一个问题是什么,如何解决?
 拆分后,某些数据在不同服务,无法直接调用本地方法查询数据
利用RestTemplate发送Http请求,实现远程调用

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

注意:启动完成后,访问下面地址:http://192.168.150.101:8848/nacos/,注意将192.168.150.101替换为你自己的虚拟机IP地址。 

模拟多个启动类:

右键启动类:点击复制配置

在其中更改启动类的端口

服务发现:

消费者需要连接nacos以拉去和订阅服务,因此服务发现的前两步与服务注册是一样,后面再加上服务调用即可:

1,引入nacos的依赖

<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2,配置nacos地址

#  给微服务起一个名字
spring:
  application:
    name: cart-service #微服务名称
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ${hm.db.pw}
  cloud:
    nacos:
      server-addr: 192.168.47.130:8848

3,服务发现

private void handleCartItems(List<CartVO> vos) {
    // TODO 1.获取商品id
    Set<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(instances.size()));
    //2.3利用ResTemplate发起http请求,得到http的相应
    /**
     * 因为使用nacos注册后,有多个端口共调用,所以不能把url写死;
     */
    ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
            instance.getUri()+"/items?ids={ids}",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<List<ItemDTO>>() {
            },
            Map.of("ids", CollUtil.join(itemIds, ","))
    );
    //判断相应是否成功
    if(!response.getStatusCode().is2xxSuccessful()){
        return;
    }
    List<ItemDTO> items =response.getBody();
    if (CollUtils.isEmpty(items)) {
        return;
    }
    // 3.转为 id 到 item的map
    Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
    // 4.写入vo
    for (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());
    }
}

OpenFeign简化注册中心代码:

使用步骤OpenFeign

1,导入依赖

<!--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,在引导类中添加一个注解

@EnableFeignClients

3,编写FeignClient

获取商品的id集合

@FeignClient("item-service")
public interface ItemClient {
    @GetMapping("/items")
    List<ItemDTO>queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

连接池: OpenFeign整合OKHttp步骤:

第一:

<!--OK http 的依赖 支持连接池-->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

第二:

做配置

#允许使用okhttp:Enables the use of the OK HTTP Client by Feign
feign:
  okhttp:
    enabled: true

 这样就可以使用了!

OpenFeign.只会在FeignClient所在包的日志级别为DEBUG时,才会输出日志。而且其日志级别有4级:
●NONE:不记录任何日志信息,这是默认值。

BAS引C:仅记录请求的方法,URL以及响应状态码和执行时间

HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
●FU儿L:记录所有请求和响应的明细,包括头信息、请求体、元数据。
由于Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。

OpenFeign日志输出:

网关路由:

用户信息从网关传递给微服务的SpringMVC的拦截器

在hmall-common中配置

配置拦截器: 

/**
 * springMVC拦截器,不做登录校验,只做用户信息的获取,不做拦截!
 */
public class UserInfoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1,获取登录用户信息
        String userInfo = request.getHeader("user-info");
        //2.判断是否获取了用户,如果有,存入ThreadLocal
        if (StrUtil.isNotBlank(userInfo)){
            UserContext.setUser(Long.valueOf(userInfo));
        }
        //3.放行
        return true;
        //return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        //使用完后删除用户信息
        UserContext.removeUser();
    }
}

添加为拦截器 (MvcConfig包下)

注意条件@ConditionalOnClass(DispatcherServlet.class)为了不再网关中生效

@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new UserInfoInterceptor());
    }
}

 

 在路径src/main/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

OpenFeign中提供了一个拦截器接口,所有由OpenFeign.发起的请求都会先调用拦截器处理请求:

实现远程调用时,用户信息的传递:

public class DefaultFeignConfig {
    //定义日志级别
    @Bean
    public Logger.Level feignLoggrLevel(){
        return Logger.Level.FULL;
    }
    //配置微服务之间的请求头传递
    @Bean
    public RequestInterceptor userInfoRequestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate Template) {
                Long userId = UserContext.getUser();
                if (userId!=null){
                    Template.header("user-info",userId.toString());
                }
            }
        };
    }
}

路由断言:

spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.47.130:8848
    gateway:
      routes:
        - id: item-service
          uri: lb://item-service
          predicates:
            - Path=/items/**,/search/**
#           默认对所有的服务都生效
      default-filters:
        - AddRequestHeader=truth,anyone long-press like button will be rich
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848
    gateway:
      routes:
        - id: item # 路由规则id,自定义,唯一
          uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表
          predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务
            - Path=/items/**,/search/** # 这里是以请求路径作为判断规则

路由过滤器:

网关登录校验请求处理流程: 

自定义过滤器: 

 在nacos中做的全局配置

spring:
  datasource:
    url: jdbc:mysql://${hm.db.host:192.168.150.101}:${hm.db.port:3306}/${hm.db.database}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: ${hm.db.un:root}
    password: ${hm.db.pw:123}
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    db-config:
      update-strategy: not_null
      id-type: auto

logging:
  level:
    com.hmall: debug
  pattern:
    dateformat: HH:mm:ss:SSS
  file:
    path: "logs/${spring.application.name}"
knife4j:
  enable: true
  openapi:
    title: ${hm.swagger.title:黑马商城接口文档}
    description: ${hm.swagger.description:黑马商城接口文档}
    email: ${hm.swagger.email:zhanghuyi@itcast.cn}
    concat: ${hm.swagger.concat:虎哥}
    url: https://www.itcast.cn
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources:
          - ${hm.swagger.package}

引依赖:

<!--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>

 拉取共享配置:

配置热更新:

当修改配置文件中的配置时,微服务无需重启即可使配置生效。

第一:在bootstrap.yaml中已经配置过了,不用特别关注!

第二:

微服务中要以特定方式读取需要热更新的配置属性

推荐第一种方式:
 

雪崩问题:

雪崩问题产生的原因是什么?
1.微服务相互调用,服务提供者出现故障或阻塞。
2.服务调用者没有做好异常处理,导致自身故障。
3.调用链中的所有服务级联失败,导致整个集群故障
解决问题的思路有哪些?

尽量避免服务出现故障或阻塞。
一、保证代码的健壮性;
二、保证网络畅通;
三、能应对较高的并发请求;

服务调用者做好远程调用异常的后备方案,避免故障扩散
解决雪崩问题的常见方案有哪些?
请求限流:限制流量在服务可以处理的范围,避免因突发流量而故障
线程隔离:控制业务可用的线程数量,将故障隔离在一定范围
服务熔断:将异常比例过高的接口断开,拒绝所有请求,直接走fallback
失败处理:定义fallback逻辑,让业务失败时不再抛出异常,而是返
回默认数据或友好提示

服务熔断:

Docshttps://b11et3un53m.feishu.cn/wiki/QfVrw3sZvihmnPkmALYcUHIDnff#B8m1djLmQohLpixhcQscVrFwnmY安装完Sentinel后在控制台输入以下命令便可启动sentinel

java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

 端口时8090

访问http://localhost:8090出现用户和密码都是sentinel

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

进行如下配置: 

Restful风格的API请求路径一般都相同,这会导致簇点资源名称重复。因此我们要修改配置,把请求方式+请求路径作
为簇点资源名称:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8090
      http-method-specify: true # 开启请求方式前缀

OpenFeign整合Sentinel 

修改cart-service模块的application.yml文件,开启Feign的sentinel功能:

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

注意:默认情况下SpringBoot项目的tomcat最大线程数是200,允许的最大连接是8492,单机测试很难打满。 

所以我们需要配置一下cart-service模块的application.yml文件,修改tomcat连接

server:
  port: 8082
  tomcat:
    threads:
      max: 50 # 允许的最大线程数
    accept-count: 50 # 最大排队等待数量
    max-connections: 100 # 允许的最大连接

Fallback:

FeignClient的Fallback有两种配置方式:
方式一:FallbackClass,无法对远程调用的异常做处理
方式二:FallbackFactory,可以对远程调用的异常做处理,通常都会选择这种


步骤一:自定义类,实现FallbackFactory,编写对某个FeignClient的fallback;逻辑:
 

步骤二:将刚刚定义的UserClientFallbackFactory注册为一个Bean:
 

步骤三:在UserClient接口中使用UserClientFallbackFactory:
 

分布式事务:

认识Seata

Seata事务管理中有三个重要的角色:
TC(Transaction Coordinator)-事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
TM(Transaction Manager)~事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
RM(Resource Manager)~资源管理器:管理分支事务,与TC交谈以注册分支事务和报告分支事务的状态

在项目中引入Seata依赖:

配置TC服务地址 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值