# microservice **Repository Path**: lan_nan/microservice ## Basic Information - **Project Name**: microservice - **Description**: 微服务 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-10-02 - **Last Updated**: 2022-10-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # microservice ## 介绍 搭建微服务架构 码云:https://gitee.com/lan_nan/microservice/tree/master/ 码云克隆:https://gitee.com/lan_nan/microservice.git ## 软件架构 聚合项目 microservice 管理个个模块 - common 公共模块,用来存放共有的对象和jar包 - consumer 消费者模块 - provider 提供者模块 - gateway 网关模块 ## 项目搭建过程 ### 1.开启nacos服务 官网:https://nacos.io/zh-cn/docs/quick-start.html #### 1-1.配置 点击运行配置 ![image-20221003144526472](README.assets/image-20221003144526472.png) ![image-20221003144638382](README.assets/image-20221003144638382.png) 添加一个Shell Script ![image-20221003144726799](README.assets/image-20221003144726799.png) ![image-20221003144942942](README.assets/image-20221003144942942.png) 出现这个运行一下 ![image-20221003144814230](README.assets/image-20221003144814230.png) #### 1-2.测试 运行起来没报错就成功了 ![image-20221003145037293](README.assets/image-20221003145037293.png) ### 2.搭建注册中心nacos #### 2-1.common ```xml microservice com.lan.mall 0.0.1-SNAPSHOT 4.0.0 common 8 8 org.springframework.boot spring-boot-dependencies 2.3.2.RELEASE pom import org.springframework.cloud spring-cloud-dependencies Hoxton.SR9 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.6.RELEASE pom import com.baomidou mybatis-plus-boot-starter 3.3.1.tmp mysql mysql-connector-java org.springframework.boot spring-boot-starter-web org.projectlombok lombok org.springframework.boot spring-boot-starter-test org.junit.jupiter junit-jupiter-engine com.alibaba fastjson 1.2.60 compile com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.cloud spring-cloud-starter-openfeign com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config org.apache.httpcomponents httpclient 4.5.8 org.apache.maven.plugins maven-compiler-plugin 3.8.1 8 8 ``` #### 2-2.consumer、provider ```xml 4.0.0 com.lan.mall 模块名称 0.0.1-SNAPSHOT 模块名称 模块名称 1.8 com.lan.mall 模块名称 0.0.1-SNAPSHOT org.springframework.boot spring-boot-maven-plugin ``` gateway的pom文件 ```xml 4.0.0 com.lan.mall gateway 0.0.1-SNAPSHOT gateway gateway 1.8 org.springframework.cloud spring-cloud-dependencies Hoxton.SR9 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.2.6.RELEASE pom import com.lan.mall common 0.0.1-SNAPSHOT com.baomidou mybatis-plus-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-gateway com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery com.alibaba.cloud spring-cloud-starter-alibaba-sentinel com.alibaba.cloud spring-cloud-alibaba-sentinel-gateway io.netty netty-codec-http 4.1.31.Final org.springframework.boot spring-boot-maven-plugin ``` #### 2-3.yml文件 ```yaml # consumer、provider、gateway都要配置 #配置端口号 server: port: 端口号,不能一致 spring: application: #链接--------nacos name: 命名,不能一致 #服务注册时,服务名必须配置 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 # nacos注册中心地址 从哪里去查找服务 config: server-addr: 127.0.0.1:8848 # nacos配置中心地址 enabled: false #关闭报错 ``` consumer、provider再写入以下内容: ```yaml # mybatis-plus根据模块是否需要再加,gateway就不需要 datasource: username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://lcalhost:3306/microservice?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml global-config: db-config: id-type: auto ``` consumer再写入以下内容: ```yaml # 配置到consumer,消费者下,实现负载均衡 # sca-provider服务负载均衡配置 赋予服务提供方策略 sca-provider: ribbon: #负载均衡组件,是ribbon组件提供了Irule接口及相关实现 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule feign: hystrix: enabled: true #打开熔断机制,如果调用不到启动备选方案 ``` 将consumer和provider运行后在nacos网站上能看到服务名称(服务名称就是spring.application.name=?) nacos网站:http://localhost:8848/nacos/ 用户名和密码都是nacos ![image-20221003151808204](README.assets/image-20221003151808204.png) ### 3.创建hello接口 我在common下创建一个User对象和一个响应的工具R,还有响应数据的枚举型REnum #### 3-1.创建类 ```java package com.lan.mall.common.bean; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String name; private Integer age; } ``` ```java package com.lan.mall.common.utils; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class R { private Integer code; private String massage; private Object data; public static R success(){ return new R(REnum.SUCCESS.getCode(), REnum.SUCCESS.getMassage(), null); } public static R success(Object data){ return new R(REnum.SUCCESS.getCode(), REnum.SUCCESS.getMassage(), data); } public static R error(){ return new R(REnum.ERROR.getCode(), REnum.ERROR.getMassage(), null); } public static R error(Object data){ return new R(REnum.ERROR.getCode(), REnum.ERROR.getMassage(), data); } public static R timeOut(){ return new R(REnum.TIME_OUT.getCode(), REnum.TIME_OUT.getMassage(), null); } } ``` ```java package com.lan.mall.common.utils; import lombok.AllArgsConstructor; import lombok.Getter; @AllArgsConstructor @Getter public enum REnum { // 成功 SUCCESS(200, "success") // 失败 , ERROR(901, "error") , TIME_OUT(902, "服务超时,请重新") ; private final Integer code; private final String massage; } ``` 在provider在创建providerHello接口创建 ```java package com.lan.mall.provider.controller; import com.lan.mall.common.bean.User; import com.lan.mall.common.utils.R; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") @RefreshScope public class UserController { @RequestMapping("/getUser") public R getUser(@RequestParam(required = false, value = "appName") String appName){ return R.success(new User(1, appName, 20)); } @RequestMapping("/hello") public R providerHello(){ return R.success("providerHello"); } } ``` #### 3-2.测试 ![image-20221003154822409](README.assets/image-20221003154822409.png) ### 4.openFeign 在consumer模块的启动类下创建RestTemplate对象并进行负载均衡、yml文件配置Ribbon提供负载均衡和重试的功能 #### 4-1.RestTemplate ```java package com.lan.mall.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScans; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableFeignClients // 配置这个扫描包,是因为有feign下的一个类一直没加载,导致启动时报错 @ComponentScans(value = { @ComponentScan("com.lan.mall.consumer.controller"), @ComponentScan("com.lan.mall.consumer.feign") }) public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } } ``` ```yaml #sca-provider服务负载均衡配置 赋予服务提供方策略 sca-provider: ribbon: #负载均衡组件,是ribbon组件提供了Irule接口及相关实现 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule feign: hystrix: enabled: true #打开熔断机制,如果调用不到启动备选方案 ``` consumer模块通过openFeign进行访问provider的访问 #### 4-2.添加Feign服务 ```java package com.lan.mall.consumer.feign; import com.lan.mall.common.utils.R; import com.lan.mall.consumer.hystrix.UserServiceFallBackFactory; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; /** * value是spring.application.name的名称,contextId是自动注入的名称 * fallbackFactory是处理服务中断和超时的问题 * 需要我们进行实现 */ @FeignClient(value = "provider", contextId = "userService", fallbackFactory = UserServiceFallBackFactory.class) public interface UserService { // 这个路径必须是全面的 @RequestMapping("/user/getUser") public R getUser(@RequestParam(required = false, value = "appName") String appName); @RequestMapping("/user/hello") public R providerHello(); } ``` fallbackFactory的实现: ```java package com.lan.mall.consumer.hystrix; import com.lan.mall.common.utils.R; import com.lan.mall.consumer.feign.UserService; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; @Component public class UserServiceFallBackFactory implements FallbackFactory { @Override public UserService create(Throwable throwable) { return new UserService() { @Override public R getUser(String appName) { return R.timeOut(); } @Override public R providerHello() { return R.timeOut(); } }; } } ``` #### 4-3.消费者的接口 ```java package com.lan.mall.consumer.controller; import com.lan.mall.common.utils.R; import com.lan.mall.consumer.feign.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/consumer") @Slf4j public class ConsumerController { @Value("${spring.application.name:consumer}") String appName; // openFeign的服务 @Autowired private UserService userService; // 负载均衡访问服务 @Autowired private RestTemplate restTemplate; /** * 通过负载均衡访问提供者服务的getUser接口 */ @RequestMapping("/getUser") public R getUser(){ String url = String.format("http://provider/user/getUser?appName=%S", appName); return restTemplate.getForObject(url, R.class); } /** * 通过远程调用接口,访问hello服务 */ @RequestMapping("/consumerHello") public R consumerHello(){ R r = userService.providerHello(); r.setData(r.getData() + " consumerHello"); return r; } } ``` #### 4-4.测试 ![image-20221003161900845](README.assets/image-20221003161900845.png) ![image-20221003161817684](README.assets/image-20221003161817684.png) ### 5.gateway #### 5-1.配置 ```yaml spring: application: name: gateway #通过网关进行访问。 cloud: nacos: discovery: #服务注册端口 server-addr: localhost:8848 config: #配置中心端口 server-addr: localhost:8848 file-extension: yml #配置文件后缀名 sentinel: #配置限流端口 transport: dashboard: localhost:8180 eager: true #开启通过服务注册中心的serbiceId创建路由 gateway: routes: #路由 - id: router01 #资源服务路由名称 uri: lb://provider #lb表示负载均衡 后面是需要进行负载均衡的服务名 predicates: #匹配规则 - Path=/provider/** #设置访问路径 以及规则 filters: - StripPrefix=1 - id: router02 #认证服务路由名称 uri: lb://consumer #lb表示负载均衡 后面是需要进行负载均衡的服务名 predicates: #谓词对象,可以定义多个谓词逻辑 - Path=/consumer/** filters: - StripPrefix=1 #去掉第一层路径 globalcors: #跨域配置(写到配置文件的好处是可以将其配置写到配置中心) corsConfigurations: #所有跨域配置只是针对ajax请求,因为ajax请求不支持跨域 '[/**]': allowedOrigins: "*" allowedHeaders: "*" allowedMethods: "*" allowCredentials: true logging: #日志 level: org.springframework.cloud.gateway: debug ``` #### 5-2.测试 ![image-20221003161919293](README.assets/image-20221003161919293.png) ![image-20221003161937024](README.assets/image-20221003161937024.png) ## springcloud的理解 springcloud就相当于将很多的接口进行细分,分成一个个模块,就比如将一个商城分为订单模块、商品模块、会员模块、仓库模块、管理员模块等,然后将这些服务分布到个个服务器上进行运行,这样可以减小服务器的压力,并且好维护,但是需要的服务器相对较多,运维难道加大 ## 注册中心的作用 服务注册中心的作用就是服务的注册和服务的发现 服务注册,就是将提供某个服务的模块信息注册到1个公共的组件上去。 服务发现,就是新注册的这个服务模块能够及时的被其他调用者发现,不管是服务新增和服务删减都能实现自动发现。 ## 配置中心的作用 配置中心就是将配置从各个应用中的配置文件拿出来,对所有的配置进行单独的统一管理。配置中心是整个微服务基础架构体系中的一个组件。总得来说,配置中心就是一种统一管理各种应用配置的基础服务组件。 ## 网关的作用 网关是一种充当转换重任的计算机系统或设备,在使用不同的通信协议,数据格式或语言,甚至体系结构完全不同的两种系统时,网关是一个翻译器。与网桥只是简单地传送信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。同时,网关也可以提供过滤和安全功能。 ## 什么是负载均衡 负载均衡就是将一个相同的服务放在不同的服务器下,通过负载均衡算法进行分配访问。