您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

Java微服务拆分架构(业务,规划,设计,实现)

时间:2023-04-05 14:08:59  来源:今日头条  作者:架构浅水湾

JAVA微服务拆分架构(业务,规划,设计,实现)

一、微服务演变过程版本1.0

几年前,小明和小皮一起创业做网上超市。小明负责程序开发,小皮负责其他事宜。当时互联网还不发达,网上超市还是蓝海。只要功能实现了就能随便赚钱。所以他们的需求很简单,只需要一个网站挂在公网,用户能够在这个网站上浏览商品、购买商品;另外还需一个管理后台,可以管理商品、用户、以及订单数据。

我们整理一下功能清单:

 

  • 网站
    • 用户注册、登录功能
    • 商品展示
    • 下单
  • 管理后台
    • 用户管理
    • 商品管理
    • 订单管理

 

由于需求简单,小明左手右手一个慢动作,网站就做好了。管理后台出于安全考虑,不和网站做在一起,小明右手左手慢动作重播,管理网站也做好了。总体架构图如下:


 

小明挥一挥手,找了家云服务部署上去,网站就上线了。上线后好评如潮,深受各类肥宅喜爱。小明小皮美滋滋地开始躺着收钱。

版本2.0

好景不长,没过几天,各类网上超市紧跟着拔地而起,对小明小皮造成了强烈的冲击。

在竞争的压力下,小明小皮决定开展一些营销手段:

 

  • 开展促销活动。比如元旦全场打折,春节买二送一,情人节狗粮优惠券等等。
  • 拓展渠道,新增移动端营销。除了网站外,还需要开发移动端App微信小程序等。
  • 精准营销。利用历史数据对用户进行分析,提供个性化服务。
  •  

 

这些活动都需要程序开发的支持。小明拉了同学小红加入团队。小红负责数据分析以及移动端相关开发。小明负责促销活动相关功能的开发。

因为开发任务比较紧迫,小明小红没有好好规划整个系统的架构,随便拍了拍脑袋,决定把促销管理和数据分析放在管理后台里,微信和移动端APP另外搭建。通宵了几天后,新功能和新应用基本完工。这时架构图如下:


 

这一阶段存在很多不合理的地方:

 

  • 网站和移动端应用有很多相同业务逻辑的重复代码。
  • 数据有时候通过数据库共享,有时候通过接口调用传输。接口调用关系杂乱。
  • 单个应用为了给其他应用提供接口,渐渐地越改越大,包含了很多本来就不属于它的逻辑。应用边界模糊,功能归属混乱。
  • 管理后台在一开始的设计中保障级别较低。加入数据分析和促销管理相关功能后出现性能瓶颈,影响了其他应用。
  • 数据库表结构被多个应用依赖,无法重构和优化。
  • 所有应用都在一个数据库上操作,数据库出现性能瓶颈。特别是数据分析跑起来的时候,数据库性能急剧下降。
  • 开发、测试、部署、维护愈发困难。即使只改动一个小功能,也需要整个应用一起发布。有时候发布会不小心带上了一些未经测试的代码,或者修改了一个功能后,另一个意想不到的地方出错了。为了减轻发布可能产生的问题的影响和线上业务停顿的影响,所有应用都要在凌晨三四点执行发布。发布后为了验证应用正常运行,还得盯到第二天白天的用户高峰期……
  • 团队出现推诿扯皮现象。关于一些公用的功能应该建设在哪个应用上的问题常常要争论很久,最后要么干脆各做各的,或者随便放个地方但是都不维护。

 

尽管有着诸多问题,但也不能否认这一阶段的成果:快速地根据业务变化建设了系统。不过紧迫且繁重的任务容易使人陷入局部、短浅的思维方式,从而做出妥协式的决策。在这种架构中,每个人都只关注在自己的一亩三分地,缺乏全局的、长远的设计。长此以往,系统建设将会越来越困难,甚至陷入不断推翻、重建的循环。

版本3.0

幸好小明和小红是有追求有理想的好青年。意识到问题后,小明和小红从琐碎的业务需求中腾出了一部分精力,开始梳理整体架构,针对问题准备着手改造。

 

要做改造,首先你需要有足够的精力和资源。如果你的需求方(业务人员、项目经理、上司等)很强势地一心追求需求进度,以致于你无法挪出额外的精力和资源的话,那么你可能无法做任何事……

 

编程的世界中,最重要的便是抽象能力。微服务改造的过程实际上也是个抽象的过程。小明和小红整理了网上超市的业务逻辑,抽象出公用的业务能力,做成几个公共服务:

 

  • 用户服务
  • 商品服务
  • 促销服务
  • 订单服务
  • 数据分析服务

 

各个应用后台只需从这些服务获取所需的数据,从而删去了大量冗余的代码,就剩个轻薄的控制层和前端。这一阶段的架构如下:


 

这个阶段只是将服务分开了,数据库依然是共用的,所以一些烟囱式系统的缺点仍然存在:

 

  1. 数据库成为性能瓶颈,并且有单点故障的风险。
  2. 数据管理趋向混乱。即使一开始有良好的模块化设计,随着时间推移,总会有一个服务直接从数据库取另一个服务的数据的现象。
  3. 数据库表结构可能被多个服务依赖,牵一发而动全身,很难调整。

 

如果一直保持共用数据库的模式,则整个架构会越来越僵化,失去了微服务架构的意义。因此小明和小红一鼓作气,把数据库也拆分了。所有持久化层相互隔离,由各个服务自己负责。另外,为了提高系统的实时性,加入了消息队列机制。架构如下:


 

完全拆分后各个服务可以采用异构的技术。比如数据分析服务可以使用数据仓库作为持久化层,以便于高效地做一些统计计算;商品服务和促销服务访问频率比较大,因此加入了缓存机制等。

 

还有一种抽象出公共逻辑的方法是把这些公共逻辑做成公共的框架库。这种方法可以减少服务调用的性能损耗。但是这种方法的管理成本非常高昂,很难保证所有应用版本的一致性。 数据库拆分也有一些问题和挑战:比如说跨库级联的需求,通过服务查询数据颗粒度的粗细问题等。但是这些问题可以通过合理的设计来解决。总体来说,数据库拆分是一个利大于弊的。

 

微服务架构还有一个技术外的好处,它使整个系统的分工更加明确,责任更加清晰,每个人专心负责为其他人提供更好的服务。在单体应用的时代,公共的业务功能经常没有明确的归属。最后要么各做各的,每个人都重新实现了一遍;要么是随机一个人(一般是能力比较强或者比较热心的人)做到他负责的应用里面。在后者的情况下,这个人在负责自己应用之外,还要额外负责给别人提供这些公共的功能——而这个功能本来是无人负责的,仅仅因为他能力较强/比较热心,就莫名地背锅(这种情况还被美其名曰能者多劳)。结果最后大家都不愿意提供公共的功能。长此以往,团队里的人渐渐变得各自为政,不再关心全局的架构设计。

问题

 

如果没有注册中心,URL异常麻烦; 大量配置,远程访问很麻烦; 大量配置,配置没有统一管理; 服务的熔断降级; 链路追踪; 需要一些服务进行支撑;
版本4.0

 

网关可以做,统一的鉴权,权限控制。


 

二、微服务拆分划分原则(面试:考核业务划分的想法)

我们拆分微服务的时候需要按照某些原则进行拆分.

 

  • 基于业务逻辑
    • 将系统中的业务按照职责范围进行识别,职责相同的划分为一个单独的服务。
  • 基于稳定性
    • 将系统中的业务模块按照稳定性进行排序。稳定的、不经常修改的划分一块;将不稳定的,经常修改的划分为一个独立服务。比如日志服务、监控服务都是相对稳定的服务,可以归到一起。
  • 基于可靠性
    • 同样,将系统中的业务模块按照可靠性进行排序。对可靠性要求比较高的核心模块归在一起,对可靠性要求不高的非核心模块归在一块。
    • 这种拆分的高明可以很好的规避因为一颗老鼠屎坏了一锅粥的单体弊端,同时将来要做高可用方案也能很好的节省机器或带宽的成本。
  • 基于高性能
    • 同上,将系统中的业务模块按照对性能的要求进行优先级排序。把对性能要求较高的模块独立成一个服务,对性能要求不高的放在一起。比如全文搜索,商品查询和分类,秒杀就属于高性能的核心模块。

 

基于上诉的拆分原则,我们可以针对骡窝窝项目进行微服务的拆分:

 

  • 游记服务
    • 目的地管理
    • 旅游攻略
    • 旅游日记
    •  
  • 评论服务
    • 旅游功能评论
    • 旅游日记评论
    • 景点评论
    • 旅行社评论
    •  
  • 用户服务
    • 用户个人中心
    • 用户积分相关
    • 黑名单/白名单
    • 粉丝关注
    •  
  • 消息服务
    • 短信通知
    • 邮件通知
    • 站内信
    •  
  • 搜索服务
    • 攻略搜索
    • 游记搜搜
    • 用户搜索
    • 景点搜索
    •  
人员配置

 

假如我们按照业务来划分,根据粒度大小,可能存在以下两种:

 

  • 第一种分为商品、交易、用户3个服务;
  • 第二种分为商品、订单、支付、物流、买家、卖家6个服务。

 

3 VS 6,这该怎么办?

如果你的团队只有9个人,那么分成3个是合理的,如果有18个人,那么6个服务是合理的。这里引入团队成员进行协助拆分。

在拆分遇到争议的时候,一般情况下我们增加一项拆分条件,虽然不是充要条件,但至少我们的答案会更加接近真理。

除了业务可能存在争议,其他的划分也会有争议,比如一个独立的服务到底需要多少人员的配置?

为什么说是三个人分配一个服务(当然,成员主要是后端人员)?

 

  • 假设是1个人,请个假、生个病都不行。一个人会遇到单点的问题,所以不合理。
  • 假设是2个人,终于有备份了,但是抽离一个后,剩下1个压力还是很大,不合理。
  • 假设是3个人,抽离一个还有2个在。而且数字3是个稳定而神奇数字,用得好事半功倍。特别是遇到技术讨论,3个人相对周全,如果是2个可能会各持己见,带有自我的偏见和盲区。

 

那么这个3是不是就是稳定的数量呢?

假设你做的是边开飞机边换引擎的重写工作,那么前期3个人都可能捉襟见肘。但是到了服务后期,你可能1个就够了。

微服务实践项目结构图


 

基础模块搭建01.parent模块

管理统一依赖;

依赖:

org.springframework.boot

spring-boot-starter-parent

2.1.4.RELEASE

1.8

Greenwich.SR1

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

02.注册中心Euraka

提供服务的注册和发现功能;

依赖:eureka-server

org.springframework.cloud

spring-cloud-starter.NETflix-eureka-server

配置application.yml

server:

port: 8761

eureka:

instance:

hostname: localhost

client:

service-url:

defaultZone: http://${eureka.instance.hostname}:${server.port}/euraka

fetch-registry: false

register-with-eureka: false

03.配置中心Config-Server

依赖

eureka-client:

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

config-server:

org.springframework.cloud

spring-cloud-config-server

配置application.yml

server:

port: 9100

spring:

application:

name: config-server

cloud:

config:

server:

git:

uri:

username:

password:

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

04.网关Zuul

依赖

eureka-client:

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

netflix-zuul:

org.springframework.cloud

spring-cloud-starter-netflix-zuul

config-client:

org.springframework.cloud

spring-cloud-config-client

配置

bootstrap.yml:

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

spring:

application:

name: zuul-server

cloud:

config:

discovery:

enabled: true

service-id: config-server

label: master

name: zuul-server

远程托管平台的文件:zuul-server.yml:

port: 9000

ribbon:

ConnectTimeout: 3000

ReadTimeout: 60000

zuul:

sensitive-headers:

forceOriginalQueryStringEncoding: true #强制采用原始请求的编码格式,即不对Get请求参数做编解码

ignored-patterns: /*-server/** #忽略匹配这个格式的路径

05.公共模块common

依赖

lombok:

org.projectlombok

lombok

web:

org.springframework.boot

spring-boot-starter-web


06.服务接口父模块provider-api


 

07.服务父模块provider-server


 

前端项目

本来由前端人员写好的前端项目;

创建frontend-website组件,和任何项目没有关系,引入依赖:

org.springframework.boot

spring-boot-starter-parent

2.1.4.RELEASE

org.springframework.boot

spring-boot-starter-web

创建启动类。

启动发出注册请求,发现访问的是8080端口,微服务的项目,不再是直接访问到某个Tomcat服务器了。而是需要通过网关:

微服务结构,请求发到 zuul 网关,当zuul接受到请求后,首先会由前置过滤器进行处理,然后在由路由过滤器具体把请求转发到后端应用,然后在执行后置过滤器把执行结果返回到请求方。

修改static/js/vue/common.js中的url访问的端口;


 

微服务架构发送请求到返回数据的执行流程:


 

聚合服务website-server结构&依赖关系处理

在provider-server模块中添加依赖,因为下面三个依赖是其模块下所有的server模块都要用到的,所以公共所有的依赖在方法父项目中添加,子项目可以继承到:

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

org.springframework.cloud

spring-cloud-config-client

配置文件

bootstrap.yml

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

spring:

application:

name: website-server

cloud:

config:

discovery:

enabled: true

service-id: config-server

label: master

name: website-server

码云的website-server.yml

server:

port: 8082

定义路由规则

码云的zuul-server.yml

zuul:

routes:

member-server-route:

path: /website/**

service-id: website-server

加启动类启动测试:

跨域问题:直接在网关位置就可以处理跨域的问题:

跨域原因:域名、端口、ip不一样的时候会产生跨域问题。默认不允许跨域的原因:对被访问的域外资源来说,服务器压力变大了,假设不信任的恶意攻击可能导致访问量过大宕机。所有需要对信任的域名做配置。预检请求会有一个缓存,除了第一次之外其他的都是一次请求。详情见单独的文档


 

在zuul-server中设置跨域:

解决跨域的问题:设置的位置,在zuul-server中的启动类中添加设置:

// 解决跨域问题

@Bean

public CorsFilter corsFilter() {

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

final CorsConfiguration config = new CorsConfiguration();

// 允许cookies跨域

config.setAllowCredentials(true);

// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin

config.addAllowedOrigin("*");

// #允许访问的头信息,*表示全部

config.addAllowedHeader("*");

// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了

config.setMaxAge(18000L);

// 允许提交请求的方法,*表示全部允许

config.addAllowedMethod("OPTIONS");

config.addAllowedMethod("HEAD");

// 允许Get的请求方法

config.addAllowedMethod("GET");

config.addAllowedMethod("PUT");

config.addAllowedMethod("POST");

config.addAllowedMethod("DELETE");

config.addAllowedMethod("PATCH");

source.registerCorsConfiguration("/**", config);

return new CorsFilter(source);

测试发现跨域的错误信息已经没有了。接下来写controller来处理我们的请求;

响应类&统一异常:

controller的设计:返回类型需要确定


 

返回值:以前单体项目返回的是Object;现在是微服务项目,我们希望有一个状态码,成功带上数据,错误带上错误信息:


 

返回类型应该是什么样的?那么应该怎么定义字段:


 

所有的返回对象都是Result对象,具体的数据封装在result对象的data中;


 

在controller中,会调用到各种业务层的业务方法:业务层中必须考虑到执行过程中出现异常的情况,需要回滚:


 

设计的错误状态码和错误信息是一一对应的,应该是常量(枚举类或者自定义类来封装他们)


 

自定义异常:来解决业务方法执行过程中出现的异常,即抛出的异常里要包含了刚刚封装了错误状态码和错误信息的对象,在throw的时候返回给调用者,由调用者(controller)来处理。


 

业务层的业务方法中写操作等,必须要保持一致性(事务),当出现异常的时候需要将异常throw出去。


 

聚合服务中,需要对有可能出现的各种异常进行统一的处理,AOP思想。出现异常,将封装了状态码和异常信息的result返回给前台,前台才能够接受到具体的错误和错误信息。


 

实现:异常的处理基本的类是所有的微服务都需要有的,所以放到common中

CodeMsg

* 封装状态码和信息

@Setter

@Getter

@NoArgsConstructor

@AllArgsConstructor

public class CodeMsg implements Serializable {

private Integer code;

private String msg;

Result

* 返回前台的数据类型

* @param

@Setter

@Getter

public class Result implements Serializable {

public static final int SUCCESS_CODE = 200;//成功码.

public static final String SUCCESS_MESSAGE = "操作成功";//成功信息.

public static final int ERROR_CODE = 500000;//错误码.

public static final String ERROR_MESSAGE = "系统异常";//错误信息.

private int code;

private String msg;

private T data;

public Result(){}

private Result(int code, String msg, T data){

this.code = code;

this.msg = msg;

this.data = data;

public static Result success(T data){

return new Result(SUCCESS_CODE,SUCCESS_MESSAGE,data);

public static Result success(String msg,T data){

return new Result(SUCCESS_CODE,msg,data);

public static Result error(CodeMsg codeMsg){

return new Result(codeMsg.getCode(),codeMsg.getMsg(),null);

public static Result defaultError(){

return new Result(ERROR_CODE,ERROR_MESSAGE,null);

public boolean hasError(){

//状态吗!=200 说明有错误.

return this.code!=SUCCESS_CODE;

BusinessException

* 自定义异常

@Setter

@Getter

public class BusinessException extends RuntimeException {

private CodeMsg codeMsg;

public BusinessException(CodeMsg codeMsg){

this.codeMsg = codeMsg;

CommonExceptionAdvice

* 公共的sdvice,不贴 @ControllerAdvice 注解,因为它是让其他服务来继承的基类

public class CommonExceptionAdvice {

@ExceptionHandler(Exception.class)

@ResponseBody

public Result hanlderDefaultException(Exception e){

e.getMessage();

return Result.defaultError();

会员服务:结构&依赖关系处理模块provider-api中添加依赖:

因为该模块下的所有的api都要提供给其他的服务来调用,所以需要在api的父项目中添加这三个依赖:

cn.wolfcode.xloud.luowowo

common

1.0.0

org.springframework.cloud

spring-cloud-starter-openfeign

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

模块member-api:暴露会员服务接口

用户的信息使用mongodb存储的,所以要引入mongodb的依赖:

org.springframework.boot

spring-boot-starter-data-mongodb

true

UserInfo

@Setter

@Getter

@Document("userInfo")@ToString

public class UserInfo implements Serializable {

public static final int GENDER_SECRET = 0; //保密

public static final int GENDER_MALE = 1; //男

public static final int GENDER_FEMALE = 2; //女

public static final int STATE_NORMAL = 0; //正常

public static final int STATE_DISABLE = 1; //冻结

@Id

protected String id;

private String nickname; //昵称

private String phone; //手机

private String emAIl; //邮箱

private String password; //密码

private int gender = GENDER_SECRET; //性别

private int level = 0; //用户级别

private String city; //所在城市

private String headImgUrl; //头像

private String info; //个性签名

private int state = STATE_NORMAL; //状态

模块member-server:会员服务,api负责暴露接口,这里负责具体的业务

添加依赖:

member-api依赖、redis依赖、fastjson依赖

cn.wolfcode.xloud.luowowo

menber-api

1.0.0

org.springframework.boot

spring-boot-starter-data-redis

com.alibaba

fastjson

1.2.47

bootstrap.yml

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka/

spring:

application:

name: member-server

cloud:

config:

discovery:

enabled: true

service-id: config-server

label: master

name: member-server,redis

member-server.yml

server:

port: 8080

spring:

data:

mongodb:

uri: mongodb://192.168.20.130:27017/member

创建微服务对应的数据库,拆分以前单体项目的表:


 

![image-2020051621441662

在模块menber-server中准备repository接口,来访问mongodb数据库的接口;

@Repository

public interface UserInfoRepository extends MongoRepository {

* 通过号码查询用户信息

* @param phone

* @return

UserInfo findByPhone(String phone);

* 通过号码和莫密码查询用户信息

* @param username

* @param password

* @return

UserInfo getByPhoneAndPassword(String username, String password);

服务之间调用:

聚合服务需要调用会员服务中的方法。需要在menber-api中用feign负载均衡将menber-server的业务方法暴露出来一个接口;

// 类似controller

@FeignClient(name = "member-server") //负载访问的服务

public interface MemberFeignApi {

@RequestMapping("/checkPhone") //映射方法

Result checkPhone(@RequestParam("phone") String phone); //映射参数

返回类型是

Result

的原因:


 

因为,基础服务也有可能出现异常,直接返会封装了错误状态码和错误信息的Result 回去,聚合服务可以直接通过result中boolean值来区分对异常的处理情况;

在member-server中,需要对接口做具体的实现了:


 

需要在server中对异常做统一的处理:

每个服务的异常有不相同的,比如注册的错和登录的错就不一样,怎么体现各个服务之间的异常差异呢?可能会有其他的异常比如 连接数据库超时的异常。自己实现具体的CoreMsg:

* member-server服务中返回的异常结果:封装code和msg

public class MemberServerCodeMsg extends CodeMsg {

//用父类的构造器来完成初始化操作

public MemberServerCodeMsg(Integer code, String msg){

super(code, msg);

public static final MemberServerCodeMsg DEFAULT_ERROR =

new MemberServerCodeMsg(500100, "会员服务繁忙!");

public static final MemberServerCodeMsg PHONE_EXIST_ERROR =

new MemberServerCodeMsg(500101, "手机号码已存在!");

异常的advice增强类,继承增强基类:

* 需要在该增强类中处理member-server中特有的异常

@ControllerAdvice

public class MemberServerExceptionAdvice extends CommonExceptionAdvice {

* 处理普通的Exception

* @param ex

* @return

@ExceptionHandler(Exception.class)

@ResponseBody

public Result handlerDefault(Exception ex){

ex.printStackTrace();

return Result.error(MemberServerCodeMsg.DEFAULT_ERROR); //返回自己的默认异常

那具体抛出哪一个server中的异常就看在呢一个server中出现异常了;


 

熔断降级:

既然可能在某个服务中会出现异常,那我们就不能让出现异常的时候使服务出现宕机而影响其它服务的正常运行。所以应该要想到对服务做熔断降级的处理;

* 对服务可能出现异常做熔断降级处理

@Component

public class UserInfoFeignHystrix implements UserInfoFeignApi{

@Override

public Result checkPhone(String phone) {

//熔断降级之后,应该做的有些处理

return null;

回退类和方法完成之后,在api接口的注解上加上:


 

注意:feign默认是没有开启Hystrix的,需要添加配置进行开启:直接放到码云中的website-server的配置文件中

# hystrix默认是关闭的,需要手动开启一下,否则一直是超时的

feign:

hystrix:

enabled: true

到此,member-server的模块就完成了,当服务出现熔断会调用到降级方法;

注入服务接口对象,完成远程调用:

注入需要引入menber-api的依赖:

返回的数据应该是什么样的,怎么解决出现异常的情况:


 

实现自己服务的返回CodeMsg:

public class WebsiteServerCodeMsg extends CodeMsg {

public WebsiteServerCodeMsg(Integer code, String msg) {

super(code, msg);

public static final WebsiteServerCodeMsg MEMBER_SERVER_ERROR =

new WebsiteServerCodeMsg(500201, "会员服务繁忙!");

public static final WebsiteServerCodeMsg DEFAULT_ERROR =

new WebsiteServerCodeMsg(500200, "聚合服务繁忙!");

controller

@RestController

@RequestMapping("/userRegister")

public class UserRegisterController {

@Autowired

private UserInfoFeignApi userInfoFeignApi;

@RequestMapping("/checkPhone")

public Result checkPhone(String phone){

//检查号码

Result result = userInfoFeignApi.checkPhone(phone);

//result返回的情况有3种,需要区分开

if (result == null){

//返回null。说明member-server服务宕机了,对应的CodeMsg应该重新设计

return Result.error(WebsiteServerCodeMsg.MEMBER_SERVER_ERROR);

//到这里,表示远程调用成功,远程的服务返回的是一个result,直接返回即可

//返回参数

return result;

还需要在启动类上加注解:@EnableFeignClients,spring才能扫描到API接口,才能创建代理对象,代理对象才能发起服务器之间的远程调用。


 

website-server对异常的统一处理:

* 对website-server的异常统一处理

@ControllerAdvice

public class WebsiteServerExceptionAdvice extends CommonExceptionAdvice{

@ExceptionHandler(Exception.class)

@ResponseBody

public Result handlerDefaultException(Exception ex){

ex.printStackTrace();

return Result.error(WebsiteServerCodeMsg.DEFAULT_ERROR);

启动测试:

两处错误:


 

最终:

微服务架构逐渐成熟,如何做到相对独立,成了当前重点考虑的问题。

我将分割了以下基础模块:

user-service 用户认证服务

shopping-cart-service 购物车服务

info-version-service 信息版本服务

user-edit-service 用户编辑服务

order-service 订单服务

seller-info-service 店铺信息

discount-Service 折扣 促销服务

inventory-service 库存服务

account-service 账户会员服务

payment-service 支付组件

promotion-service 促销服务Base

Search-service 搜索服务

concern-Service 互动服务

tracks-service 足迹

Cms Search-service CMS搜索服务

Seller-service 商户认证服务

product-Mgr-service 商品管理服务

Order-mgr-service 订单服务

Catalog-mgr-service 产品目录

Seller-edit-service 商户编辑服务

sendout-service 发货服务/推送

Grant-service 权限服务

employee-service 雇员认证服务

employee-mgr-service 雇员服务

Promotion-mgr-Service 促销管理

static-service 静态化服务

product-Mgr-service 商品管理服务

Order-mgr-service 订单服务

Catalog-mgr-service 产品目录

dict-service 字典管理服务

Cms-service CMS服务

Seller-edit-service 商户编辑服务



Tags:微服务   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  Search: 微服务  点击:(5)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  Search: 微服务  点击:(115)  评论:(0)  加入收藏
九条微服务最佳实践,你学会了哪条?
微服务之间连贯一致的代码库对于可维护性至关重要。保持代码成熟度相似,可确保系统统一演进,防止服务间出现性能、安全性和功能差异。在开发微服务时,我们需要遵循哪些最佳实践...【详细内容】
2024-01-05  Search: 微服务  点击:(99)  评论:(0)  加入收藏
Go微服务入门到容器化实践
Go微服务入门到容器化实践Go 是一门高效、现代化、快速增长的编程语言,非常适合构建 Web 应用程序。而 Docker 是一种轻量级的容器化技术,能够使得您的应用程序在任何地方运行...【详细内容】
2024-01-01  Search: 微服务  点击:(63)  评论:(0)  加入收藏
微服务全做错了!谷歌提出新方法,成本直接降为1/9!
2023,微服务“水逆”之年。长期以来,不管大厂还是小厂,微服务都被认为是云原生服务应用程序架构的事实标准,然而2023,不止那位37signals的DHH决心下云,放弃微服务,就连亚马逊和谷歌...【详细内容】
2023-12-29  Search: 微服务  点击:(120)  评论:(0)  加入收藏
微服务架构中的数据一致性
在微服务中,一个逻辑上原子操作可以经常跨越多个微服务。即使是单片系统也可能使用多个数据库或消息传递解决方案。使用多个独立的数据存储解决方案,如果其中一个分布式流程参...【详细内容】
2023-12-27  Search: 微服务  点击:(143)  评论:(0)  加入收藏
监控 Spring Cloud 微服务的实践方案
一、简介Spring Cloud是一个基于Spring Boot实现的微服务框架,它提供了丰富的微服务功能,如分布式配置、服务注册与发现、服务熔断、负载均衡等。为了更好地管理和监控这样复...【详细内容】
2023-12-19  Search: 微服务  点击:(144)  评论:(0)  加入收藏
聊聊微服务链路服务
微服务架构图片如果有用户反馈某个页面很慢,我们知道这个页面的请求调用链是 A -----> C -----> B -----> D(图片有误),怎么来定位是由哪个服务引起的问题呢? 更进一步,如果...【详细内容】
2023-12-15  Search: 微服务  点击:(126)  评论:(0)  加入收藏
选择适合微服务的编程语言,让你的工作事半功倍!
讨论编程语言就像是一场政治辩论。每个开发者都会过分捍卫他/她所使用的编程语言。然而,编程语言应该被看作是它们真正是的东西,即一种工作工具。每种编程语言都有特定的目的...【详细内容】
2023-12-14  Search: 微服务  点击:(178)  评论:(0)  加入收藏
Eureka: 微服务架构中不可或缺的服务治理工具
Eureka是Netflix开源的一款用于服务治理的工具,它是NetflixOSS(OpenSourceSoftware)项目的一部分,主要用于实现微服务架构中的服务注册与发现。在当今庞大而复杂的微服务系统中,E...【详细内容】
2023-12-14  Search: 微服务  点击:(192)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(12)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(6)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(16)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(115)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条