当前位置: 首页 > news >正文

上海php网站开发推广效果最好的平台

上海php网站开发,推广效果最好的平台,新年祝福语在线制作网站,益阳房地产网站建设SpringCloud 微服务单体框架微服务框架SpringCloud微服务拆分微服务差分原则拆分商品服务拆分购物车服务拆分用户服务拆分交易服务拆分支付服务服务调用RestTemplate远程调用 微服务拆分总结 服务治理注册中心Nacos注册中心服务注册服务发现 OpenFeign实现远程调用快速入门引入…

SpringCloud

  • 微服务
    • 单体框架
    • 微服务框架
    • SpringCloud
    • 微服务拆分
      • 微服务差分原则
      • 拆分商品服务
      • 拆分购物车服务
      • 拆分用户服务
      • 拆分交易服务
      • 拆分支付服务
      • 服务调用
        • RestTemplate
        • 远程调用
      • 微服务拆分总结
    • 服务治理
      • 注册中心
        • Nacos注册中心
        • 服务注册
        • 服务发现
    • OpenFeign实现远程调用
      • 快速入门
        • 引入依赖
        • 启用OpenFeign
        • 编写OpenFeign客户端
      • 底层连接池改造
      • 最佳实现--新建api模块
      • 日志输出
      • 总结
    • 网关
      • 快速配置
      • 路由属性
      • 路由过滤器
      • 网关登录校验
        • 自定义过滤器
        • 实现登录校验
        • 网关传递用户
        • OpenFeign传递用户
    • 配置管理
      • 配置共享
      • 配置热更新
      • 动态路由
    • 服务保护
      • 雪崩问题
      • 服务保护方案
        • 请求限流
        • 线程隔离
        • 失败处理
          • failback
        • 服务熔断
      • Sentinel
    • 分布式事务
      • Seata框架

微服务

单体框架

将所有功能集中在一个显目中开发,打成一个包部署。

优点:
框架简单
部署成本低

缺点:
团队协作成本高
系统发布效率低
系统可以性差

微服务框架

服务化,把单体框架中的功能模块拆分成为多个独立项目。
在这里插入图片描述

SpringCloud

java领域最全面的微服务组件的集合
在这里插入图片描述

微服务拆分

在这里插入图片描述

微服务差分原则

在这里插入图片描述

拆分商品服务

在这里插入图片描述

拆分购物车服务

在这里插入图片描述

拆分用户服务

在这里插入图片描述

拆分交易服务

在这里插入图片描述

拆分支付服务

在这里插入图片描述

服务调用

在拆分的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了item-service服务,导致我们无法查询。
最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用。
因此,现在查询购物车列表的流程变成了这样:
在这里插入图片描述
思考:
假如我们在cart-service中能模拟浏览器,发送http请求到item-service,是不是就实现了跨微服务的远程调用了呢?
那么:我们该如何用Java代码发送Http的请求呢?

RestTemplate

Spring给我们提供了一个RestTemplate的API,可以方便的实现Http请求的发送。

远程调用

在这里插入图片描述
在这里插入图片描述
先将RestTemplate注册为一个Bean:

接下来,我们修改cart-service中的com.hmall.cart.service.impl.CartServiceImpl的handleCartItems方法,发送http请求到item-service:

package com.hmall.cart.service.impl;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.cart.domain.dto.CartFormDTO;
import com.hmall.cart.domain.dto.ItemDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
import com.hmall.cart.mapper.CartMapper;
import com.hmall.cart.service.ICartService;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import lombok.RequiredArgsConstructor;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;/*** <p>* 订单详情表 服务实现类* </p>** @author 虎哥* @since 2023-05-05*/
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {// private final IItemService itemService;private final RestTemplate restTemplate;@Overridepublic void addItem2Cart(CartFormDTO cartFormDTO) {// 1.获取登录用户Long userId = UserContext.getUser();// 2.判断是否已经存在if (checkItemExists(cartFormDTO.getItemId(), userId)) {// 2.1.存在,则更新数量baseMapper.updateNum(cartFormDTO.getItemId(), userId);return;}// 2.2.不存在,判断是否超过购物车数量checkCartsFull(userId);// 3.新增购物车条目// 3.1.转换POCart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);// 3.2.保存当前用户cart.setUserId(userId);// 3.3.保存到数据库save(cart);}@Overridepublic List<CartVO> queryMyCarts() {// 1.查询我的购物车列表List<Cart> carts = lambdaQuery().eq(Cart::getUserId, 1L /*TODO UserContext.getUser()*/).list();if (CollUtils.isEmpty(carts)) {return CollUtils.emptyList();}// 2.转换VOList<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);// 3.处理VO中的商品信息handleCartItems(vos);// 4.返回return vos;}private void handleCartItems(List<CartVO> vos) {// TODO 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());}}@Overridepublic void removeByItemIds(Collection<Long> itemIds) {// 1.构建删除条件,userId和itemIdQueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();queryWrapper.lambda().eq(Cart::getUserId, UserContext.getUser()).in(Cart::getItemId, itemIds);// 2.删除remove(queryWrapper);}private void checkCartsFull(Long userId) {int count = lambdaQuery().eq(Cart::getUserId, userId).count();if (count >= 10) {throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", 10));}}private boolean checkItemExists(Long itemId, Long userId) {int count = lambdaQuery().eq(Cart::getUserId, userId).eq(Cart::getItemId, itemId).count();return count > 0;}
}

在这里插入图片描述

微服务拆分总结

在这里插入图片描述

服务治理

注册中心

Nacos注册中心

在这里插入图片描述

将资料中的SQL文件导入到你Docker中的MySQL容器中

之后执行docker命令:

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.61.130:8848/nacos/

服务注册

把item-service注册到Nacos,步骤如下:

  • 引入依赖
<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • 配置Nacos地址
spring:application:name: item-servicecloud:nacos:server-addr: 192.168.61.130:8848 # nacos地址
  • 重启
    在这里插入图片描述
    在这里插入图片描述
服务发现

服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:

  • 引入依赖
<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • 配置Nacos地址
spring:cloud:nacos:server-addr: 192.168.150.101:8848
  • 发现并调用服务(这个太麻烦了,之后用OpenFeign)
    在这里插入图片描述

服务发现需要用到一个工具,DiscoveryClient,SpringCloud已经帮我们自动装配,我们可以直接注入使用:
private final DiscoveryClient discoveryClient;

接下来,我们就可以对原来的远程调用做修改了,之前调用时我们需要写死服务提供者的IP和端口:
但现在不需要了,我们通过DiscoveryClient发现服务实例列表,然后通过负载均衡算法,选择一个实例去调用:

OpenFeign实现远程调用

是一个声明式的http客户端,作用就是基于SpringMVC的常用注解,帮我们优雅的实现http请求的发送

现在用的最新负载均衡:引入loadbalancer

快速入门

引入依赖

在cart-service服务的pom.xml中引入OpenFeign的依赖和loadBalancer依赖:

org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-loadbalancer
启用OpenFeign

接下来,我们在cart-service的CartApplication启动类上添加注解,启动OpenFeign功能:
在这里插入图片描述

编写OpenFeign客户端

在cart-service中,定义一个新的接口,编写Feign客户端:
其中代码如下:

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.List;@FeignClient("item-service")
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}
  • @FeignClient(“item-service”) :声明服务名称
  • @GetMapping :声明请求方式
  • @GetMapping(“/items”) :声明请求路径
  • @RequestParam(“ids”) Collection ids :声明请求参数
  • List :返回值类型

OpenFeign就可以利用动态代理帮我们实现这个方法,并且向http://item-service/items发送一个GET请求,携带ids为请求参数,并自动将返回值处理为List。
我们只需要直接调用这个方法,即可实现远程调用了。

底层连接池改造

在这里插入图片描述

最佳实现–新建api模块

在这里插入图片描述

日志输出

在这里插入图片描述

在这里插入图片描述

总结

在这里插入图片描述

网关

网络的关口,负责请求的路由、转发、身份验证
在这里插入图片描述

快速配置

在这里插入图片描述
新建hm-gateway模板

pox.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>hmall</artifactId><groupId>com.heima</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>hm-gateway</artifactId><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--nacos discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

启动类

package com.hmall.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}

配置路由规则application.yaml

server:port: 8080
spring:application:name: gatewaycloud:nacos:server-addr: 192.168.61.130:8848gateway:routes:- id: item # 路由规则id,自定义,唯一uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务- Path=/items/**,/search/** # 这里是以请求路径作为判断规则- id: carturi: lb://cart-servicepredicates:- Path=/carts/**- id: useruri: lb://user-servicepredicates:- Path=/users/**,/addresses/**- id: tradeuri: lb://trade-servicepredicates:- Path=/orders/**- id: payuri: lb://pay-servicepredicates:- Path=/pay-orders/**

四个属性含义如下:

  • id:路由的唯一标示
  • predicates:路由断言,其实就是匹配条件
  • filters:路由过滤条件
  • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

路由属性

路由过滤器

在这里插入图片描述

网关登录校验

ThreadLocal的使用,线程之间共享数据,所以不能使用
在这里插入图片描述

在这里插入图片描述

自定义过滤器

在这里插入图片描述

实现登录校验
网关传递用户

步骤一:在网关登录校验过滤器中,把获取到的用户信息写入请求头

        // 5.如果有效,传递用户信息String userInfo = userId.toString();ServerWebExchange swe = exchange.mutate().request(builder -> builder.header("user-info", userInfo)).build();

步骤二:在hm-common中编写SpringMVC拦截器,获取登录用户

package com.hmall.common.interceptors;import cn.hutool.core.util.StrUtil;
import com.hmall.common.utils.UserContext;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class UserInfoInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取请求头中的用户信息String userInfo = request.getHeader("user-info");// 2.判断是否为空if (StrUtil.isNotBlank(userInfo)) {// 不为空,保存到ThreadLocalUserContext.setUser(Long.valueOf(userInfo));}// 3.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserContext.removeUser();}
}
package com.hmall.common.config;import com.hmall.common.interceptors.UserInfoInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@ConditionalOnClass(DispatcherServlet.class) //有springMVC,配置才有效
public class MvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserInfoInterceptor());}
}

在这里插入图片描述

OpenFeign传递用户

有些业务是比较复杂的,请求到达微服务后还需要调用其它多个微服务。
在这里插入图片描述
由于微服务获取用户信息是通过拦截器在请求头中读取,因此要想实现微服务之间的用户信息传递,就必须在微服务发起调用时把用户信息存入请求头。

微服务之间调用是基于OpenFeign来实现的,Feign中提供的一个拦截器接口:feign.RequestInterceptor

package com.hmall.api.config;import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {// 获取登录用户Long userId = UserContext.getUser();if(userId == null) {// 如果为空则直接跳过return;}// 如果不为空则放入请求头中,传递给下游微服务template.header("user-info", userId.toString());}};}
}

配置管理

配置共享

我们可以把微服务共享的配置抽取到Nacos中统一管理,这样就不需要每个微服务都重复配置了。

  • 在Nacos中添加共享配置
  • 微服务拉取配置

配置热更新

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

  <!--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>
spring:application:name: cart-service # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.61.131 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-jdbc.yaml # 共享mybatis配置- dataId: shared-log.yaml # 共享日志配置- dataId: shared-swagger.yaml # 共享日志配置
server:port: 8084
feign:okhttp:enabled: true # 开启OKHttp连接池支持
hm:db:database: hm-cartswagger:title: 购物车服务接口文档package: com.hmall.cart.controller
package com.hmall.cart.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {private Integer maxItems;}
    private void checkCartsFull(Long userId) {int count = lambdaQuery().eq(Cart::getUserId, userId).count();if (count >= cartProperties.getMaxItems()) {throw new BizIllegalException(StrUtil.format("用户购物车商品数量不能超过{}", cartProperties.getMaxItems()));}}

动态路由

网关的路由配置全部是在项目启动时由org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator在项目启动的时候加载,并且一经加载就会缓存到内存中的路由表内(一个Map),不会改变。也不会监听路由变更,所以,我们无法利用上节课学习的配置热更新来实现路由更新。

因此,我们必须监听Nacos的配置变更,然后手动把最新的路由更新到路由表中。这里有两个难点:

  • 如何监听Nacos配置变更?
  • 如何把路由信息更新到路由表?

服务保护

雪崩问题

微服务调用某个服务故障,引起整个链路中所有微服务都不可以

在这里插入图片描述

在这里插入图片描述

服务保护方案

在这里插入图片描述

请求限流

限制访问接口的并发量,避免因服务激增出现故障

在这里插入图片描述

线程隔离

限定每个业务能使用的线程数量而将业务故障隔离, 避免故障扩散

比如,查询购物车的时候需要查询商品,为了避免因商品服务出现故障导致购物车服务级联失败,我们可以把购物车业务中查询商品的部分隔离起来,限制可用的线程资源。这样,即便商品服务出现故障,最多导致查询购物车业务故障,并且可用的线程资源也被限定在一定范围,不会导致整个购物车服务崩溃。

所以,我们要对查询商品的FeignClient接口做线程隔离。

失败处理

定义fallback逻辑,让业务失败时不再抛出异常,而是走fallback逻辑

failback

FeiClient的Fallback配置,FallbackFactory,可以对远程调用的异常做处理,通常都会选择这种
http://192.168.61.133:8848/nacos/

服务熔断

由熔断器统计请求的异常比例,超出阈值则熔断该业务,拦截该接口请求

在这里插入图片描述
状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
  • open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态持续一段时间后会进入half-open状态
  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。
    • 请求成功:则切换到closed状态
    • 请求失败:则切换到open状态

Sentinel

Sentinel 的使用可以分为两个部分:

  • 核心库(Jar包):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。在项目中引入依赖即可实现服务限流、隔离、熔断等功能。
  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

分布式事务

在分布式系统中,如果一个业务需要多个服务合作完成,而且每一个服务都有事务,多个事务必须同时成功或失败

分支事务:每个服务的事务
全局事务:整个业务
在这里插入图片描述

Seata框架

在这里插入图片描述

http://www.zhongyajixie.com/news/11114.html

相关文章:

  • 网站建设 设计seo排名点击首页
  • 怎么做多个域名指向一个网站今日腾讯新闻最新消息
  • 湖南最新疫情公布在线工具seo
  • 网站制作培训一般要多少钱域名停靠网页推广大全
  • 建设网站的费用公司地址怎么弄在百度上显示
  • 网站开发的工作总结软文接单平台
  • 做网页课件的网站国家高新技术企业名单
  • 做黄色网站的成本百度权重1
  • 玉器哪家网站做的好seo技术有哪些
  • 仿站网站建设淘宝关键词优化怎么弄
  • 寿光网站建设公司网络优化工程师需要学什么
  • 可以申请域名的网站腾讯新闻发布平台
  • 建设部网站核对编号重庆seo排名电话
  • 南京工大建设工程技术有限公司网站营销型企业网站
  • 网站建设 骏域网络建设专家广州网站推广平台搭建
  • 小荷特卖的网站谁做的windows优化大师兑换码
  • 做网站有自己的服务器吗宁夏百度推广代理商
  • 临海做网站自动连点器
  • 国内漂亮的企业网站系统推广公司
  • 做窗帘的效果图网站网络营销方式有哪些分类
  • 香港外贸网站建设2023重大新闻事件10条
  • 给WordPress添加视频播放页seowhy
  • 集团门户网站建设公司如何做百度竞价推广
  • 电脑制作网站的软件深圳推广公司哪家正规
  • 网站推广建设阶段深圳seo优化服务商
  • 做旅游网站选什么空间seo快速排名系统
  • 中央经济工作会议2023年7月召开搜索引擎优化排名品牌
  • 新能源网站建设百度引擎搜索入口
  • 网站建设单位哪家好2023智慧树网络营销答案
  • wordpress 离线编辑知乎seo