概述
Nacos配置管理
配置热更新:当service的配置有变更时,不用项目重新启动就能nacos自动加载到更新内容。而这项工作交给配置管理服务,它能读取配置。nacos配置管理服务就是nacos本身。
1.1、添加统一配置管理并读取
- 步骤
-
1)添加配置信息
- 在nacos中添加配置信息
- 在弹出表单中填写配置信息
配置信息:只需要添加需要变更的配置信息,如数据库信息不用修改,则可以不添加进去
- 在nacos中添加配置信息
-
2)在userservice的pom.xml中引入Nacos的配置管理客户端依赖:
<!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
3)在userservice中的resources目录下添加bootstrap.yaml文件,这是引导文件,优先级高于application.yml
spring: application: name: userservice # 服务名称 profiles: active: dev #开发环境,这里是dev cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名
注意:
1.根据spring.cloud.nacos.server-addr获取nacos地址
2.根据${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作为文件id,来读取配置。
3.该文件有的东西在userservice的application.xml中要删除 -
4)读取nacos配置测试:
在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:添加@Value注解获取dateformat值@Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Value("${pattern.dateformat}") private String dateformat; @GetMapping("now") public String now(){ return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); } // ...略 }
-
5)可看到结果:
-
1.2、配置热更新
- 配置热更新:修改nacos中的配置后,微服务中无需重启即可让配置生效
- 步骤:
-
法一:在@Value注入的变量所在类上添加注解@RefreshScope
-
法二:(推荐⭐)使用@ConfigurationProperties注解代替@Value注解。
1.在user-service服务中,添加一个类config.PatternProperties.class,读取patterrn.dateformat属性@Component @Data @ConfigurationProperties(prefix = "pattern") public class PatternProperties { private String dateformat; }
2.在测试类中注入PatternProperties对象,调用方法测试
@Slf4j @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Autowired private PatternProperties patternProperties; @GetMapping("now") public String now(){ return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat())); } // 略 }
-
1.3、配置文件的三种方式以及优先级
-
配置文件的三种方式:
- 文件名添加了namespace:
[spring.application.name]-[spring.profiles.active].yaml
,例如:userservice-dev.yaml - 多环境配置文件:文件名未添加namespace:(可以被多个环境共享)
[spring.application.name].yaml
,例如:userservice.yaml - 本地配置文件:
如:application.yml
- 文件名添加了namespace:
-
配置文件的优先级
服务名-profile.yaml>服务名.yaml>本地配置application.yml
1.4、搭建Nacos集群
- 搭建步骤
-
1、搭建数据库,初始化数据库表结构
- 这里以单点数据库为例
- 新建名为nacos的数据库,导入SQL
由于mysql5.5不支持该SQL语句,SQL此处不粘贴了,太长了,需要重新下载mysql5.7,
教程:https://blog.csdn.net/weidong_y/article/details/79763756
安装目录:C:Program FilesMySQLMySQL Server 5.7bin
-
2、下载nacos安装包
-
3、配置nacos
-
进入nacos的conf目录
- 修改配置文件cluster.conf.example,重命名为cluster.conf
- 在cluster.conf中添加内容(3个结点的IP+端口)
127.0.0.1:8845 127.0.0.1.8846 127.0.0.1.8847
-
修改application.properties文件,添加数据库配置
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=root
-
-
4、启动nacos集群
- 将nacos文件夹复制三份,分别命名为:nacos1、nacos2、nacos3
- 然后分别修改三个文件夹中的application.properties
nacos1为:server.port=8845
nacos2为:server.port=8846
nacos3为:server.port=8847 - 分别启动三个nacos节点:进入bin目录,startup.cmd
- 将nacos文件夹复制三份,分别命名为:nacos1、nacos2、nacos3
-
5、nginx反向代理
- 打开ngix的conf目录,找到ngix.conf文件,在http的{}中添加
# 添加集群的IP和端口 upstream nacos-cluster { server 127.0.0.1:8845; server 127.0.0.1:8846; server 127.0.0.1:8847; } server { listen 80; server_name localhost; location /nacos { proxy_pass http://nacos-cluster; } }
- 运行nginx
进入nginx的安装目录,执行:start nginx.exe
- 打开ngix的conf目录,找到ngix.conf文件,在http的{}中添加
-
6、测试
- 运行集群:在浏览器访问:http://localhost/nacos
- 为集群添加服务
- 在userservice的bootstrap.yml中配置:
spring: cloud: nacos: server-addr: localhost:80 # Nacos地址
- 当给userservice添加配置后,对应的nacos数据库的config_info表就会有信息
-
Feign远程调用
2.1、基于Feign远程调用
-
利用RestTemplate发起远程调用的代码:
String url = "http://userservice/user/" + order.getUserId(); User user = restTemplate.getForObject(url, User.class);
- 缺点:
代码可读性差,编程体验不统一
参数复杂URL难以维护
- 缺点:
-
Feign:是一个声明式的http客户端,
- 官方地址:https://github.com/OpenFeign/feign
- 作用:就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。
-
Fegin的使用步骤如下:
-
1)引入依赖
我们在order-service服务的pom文件中引入feign的依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
2)添加注解
在order-service的启动类添加注解**@EnableFeignClients**开启Feign的功能:
@EnableFeignClients @MapperScan("cn.itcast.order.mapper") @SpringBootApplication public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
-
3)编写Feign的客户端
在order-service中新建一个接口clients.UserClient.interface,内容如下:
package cn.itcast.order.client; import cn.itcast.order.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient("userservice") public interface UserClient { @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); }
服务名称:userservice(要求在nacos注册过)
请求方式:GET
请求路径:/user/{id}
请求参数:Long id
返回值类型:User -
4)测试
修改order-service中的OrderService类中的queryOrderById方法,使用Feign客户端代替RestTemplate:
@Service public class OrderService { @Autowired private OrderMapper orderMapper; @Autowired private UserClient userClient; public Order queryOrderById(Long orderId) { // 1.查询订单 Order order = orderMapper.findById(orderId); User user = userClient.findById(order.getUserId()); order.setUser(user); // 4.返回 return order; } }
-
2.2、自定义配置(如日志配置)
- Feign可以支持很多的自定义配置,如下表所示:
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。
- 日志配置
- 日志的级别分为四种:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
- FULL:(调错用)记录所有请求和响应的明细,包括头信息、请求体、元数据。
- 配置日志信息
-
方法一:配置文件方式
基于配置文件修改feign的日志级别可以针对单个服务:feign: client: config: userservice: # 针对某个微服务的配置 loggerLevel: FULL # 日志级别
也可以针对所有服务:
feign: client: config: default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置 loggerLevel: FULL # 日志级别
-
方法二:java代码方式
也可以基于Java代码来修改日志级别,先声明一个类,然后在orderservice中声明一个Logger.Level的对象:public class DefaultFeignConfiguration { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.BASIC; // 日志级别为BASIC } }
如果要全局生效,将其放到启动类OrderApplication的@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
如果是局部生效,则把它放到对应UserClient的@FeignClient这个注解中:
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
-
- 日志的级别分为四种:
2.3、性能优化
2.3.1 日志优化
- 优化1.日志级别尽量使用basic
2.3.2 连接池优化
-
Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:
URLConnection:默认实现,不支持连接池
Apache HttpClient :支持连接池
OKHttp:支持连接池 -
优化:使用连接池代替默认的URLConnection
-
这里我们用Apache的HttpClient来演示
-
1)引入依赖
在order-service的pom文件中引入Apache的HttpClient依赖或okhttp:<!--httpClient的依赖 --> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
-
2)配置连接池
在order-service的application.yml中添加配置:
feign: client: config: default: # default全局的配置 loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息 httpclient: enabled: true # 开启feign对HttpClient的支持 max-connections: 200 # 最大的连接数 max-connections-per-route: 50 # 每个路径的最大连接数
-
2.4、提取共同的UserAPI
2.4.1.继承方式
-
一样的代码可以通过继承来共享:
1)定义一个API接口,利用定义方法,并基于SpringMVC注解做声明。
2)Feign客户端和Controller都集成改接口
-
优点:
简单
实现了代码共享 -
缺点:
服务提供方、服务消费方紧耦合
参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解
2.4.2.抽取方式
-
概念:将Feign的Client抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。
例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。
- 实践:
-
1 抽取
1)首先创建一个module,命名为feign-api:
2)在feign-api中然后引入feign的starter依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
3)然后,order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
-
2 在order-service中使用feign-api
1)首先,删除order-service中的UserClient、User、DefaultFeignConfiguration等类或接口。
2)在order-service的pom文件中中引入feign-api的依赖:<dependency> <groupId>cn.itcast.demo</groupId> <artifactId>feign-api</artifactId> <version>1.0</version> </dependency>
3)修改order-service中的所有与上述三个组件有关的导包部分,改成导入feign-api中的包
4)解决OrderApplication扫描不到cn.itcast.feign包的问题
法一:在OrderApplication中指定Feign应该扫描的包:@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
法二:在OrderApplication中指定需要加载的Client接口:
@EnableFeignClients(clients = {UserClient.class})
-
Gateway服务网关
3.1、网关介绍
-
网关:Gateway网关是我们服务的守门神,所有微服务的统一入口
-
网关功能:
身份认证、权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。
-
网关的实现
- gateway:pringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
- zuul:Zuul是基于Servlet的实现,属于阻塞式编程
3.2、快速入门
- 基本步骤如下:
- 创建SpringBoot工程gateway,引入网关依赖
- 编写启动类
- 编写基础配置和路由规则
- 启动网关服务进行测试
- 具体步骤:
-
1)创建gateway服务的项目,引入依赖
引入依赖:<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
-
2)编写启动类
package cn.itcast.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); } }
-
3)编写基础配置和路由规则
- a. gateway基本配置信息
- b. 路由配置包括:
1)路由id:路由唯一标识
2)路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
3)路由断言(predicates):判断路由的规则,
4)路由过滤器(filters):对请求或响应做处理 - 配置:
创建gateway的application.yml文件,内容如下:
#服务端口 server: port: 10010 spring: #服务名称 application: name: gateway #服务注册 cloud: #注册到哪个nacos nacos: server-addr: localhost:8848 #nacos地址 #网关信息 gateway: routes: # userservice的路由 - id: user-service uri: lb://userservice predicates: - Path=/user/** # orderservice的路由 - id: order-service uri: lb://orderservice predicates: - Path=/order/**
-
4)重启测试
重启网关,访问http://localhost:10010/user/1时,符合/user/**
规则,请求转发到uri:http://userservice/user/1,得到了结果:
-
3.3、路由断言工厂
-
断言工厂作用:将配置文件中的断言规则字符串,转变为路由判断的条件
如:Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来处理的 -
SpringCloudGateway的其他断言工厂
名称 说明 示例 After 是某个时间点后的请求 - After=2037-01-20T17:42:47.789-07:00[America/Denver] Before 是某个时间点之前的请求 - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] Between 是某两个时间点之前的请求 - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] Cookie 请求必须包含某些cookie - Cookie=chocolate, ch.p Header 请求必须包含某些header - Header=X-Request-Id, d+ Host 请求必须是访问某个host(域名) - Host=.somehost.org,.anotherhost.org Method 请求方式必须是指定方式 - Method=GET,POST Path 请求路径必须符合指定规则 - Path=/red/{segment},/blue/** Query 请求参数必须包含指定参数 - Query=name, Jack或者- Query=name RemoteAddr 请求者的ip必须是指定范围 - RemoteAddr=192.168.1.1/24 Weight 权重处理 例如After:
当2022-04-13之前访问localhost:10010/order/101会失败,之后访问会成功
3.4、过滤器
3.4.1 路由过滤器配置
-
GatewayFilter:是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
-
Spring提供了31种不同的路由过滤器工厂。例如:(见官网)
名称 说明 AddRequestHeader 给当前请求添加一个请求头 RemoveRequestHeader 移除请求中的一个请求头 AddResponseHeader 给响应结果中添加一个响应头 RemoveResponseHeader 从响应结果中移除有一个响应头 RequestRateLimiter 限制请求的流量 -
添加请求头过滤器示例:
- 需求:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!(格式:key=value)
- 步骤:
修改gateway服务的application.yml文件,添加路由过滤即可spring: cloud: gateway: routes: - id: user-service uri: lb://userservice predicates: - Path=/user/** filters: # 过滤器 - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
3.4.2 默认过滤器
-
默认过滤器default-filters:对所有的路由都起作用
spring: cloud: gateway: routes: - id: user-service uri: lb://userservice predicates: - Path=/user/** default-filters: # 全局过滤器 - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
3.4.3 全局过滤器(自定义过滤器)
-
全局过滤器作用:处理一切进入网关的请求和微服务响应,逻辑自己编写
-
与默认过滤器区别:1、处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。2、区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。
-
定义方式:实现GlobalFilter接口
public interface GlobalFilter { /** * 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理 * * @param exchange 请求上下文,里面可以获取Request、Response等信息 * @param chain 用来把请求委托给下一个过滤器 * @return {@code Mono<Void>} 返回标示当前过滤器业务结束 */ Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); }
-
定义案例:
-
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
参数中是否有authorization;authorization参数值是否为admin
如果同时满足则放行,否则拦截 -
实现:
在gateway中定义一个过滤器:
package cn.itcast.gateway.filters; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; //order值越小,过滤器优先级越高 @Order(-1) @Component public class AuthorizeFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1.获取请求参数 MultiValueMap<String, String> params = exchange.getRequest().getQueryParams(); // 2.获取authorization参数 String auth = params.getFirst("authorization"); // 3.校验 if ("admin".equals(auth)) { // 放行 return chain.filter(exchange); } // 4.拦截 // 4.1.禁止访问,设置状态码 exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 4.2.结束处理 return exchange.getResponse().setComplete(); } }
设置过滤器的优先级:1、@order注解;2、实现Ordered接口,在类中重写getOrder(),令其返回值为-1
-
3.4.5 过滤器执行顺序
- 执行原理:请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
- 排序规则:
1.每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter的顺序执行。
2.GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
3.路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
3.5、网关的cors跨域配置
- 跨域:
-
含义:域名不一致就是跨域
-
跨域种类:
域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
域名相同,端口不同:localhost:8080和localhost8081 -
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
-
解决方案:CORS,这个以前应该学习过,这里不再赘述了。不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html
-
- gateway解决跨域问题:
-
网关处理跨域采用的是CORS方案,并且只需要简单配置即可实现
在gateway服务的application.yml文件中,添加下面的配置:spring: cloud: gateway: # 。。。 globalcors: # 全局的跨域处理 add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题 corsConfigurations: '[/**]': allowedOrigins: # 允许哪些网站的跨域请求 - "http://localhost:8090" allowedMethods: # 允许的跨域ajax的请求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowedHeaders: "*" # 允许在请求中携带的头信息 allowCredentials: true # 是否允许携带cookie maxAge: 360000 # 这次跨域检测的有效期
-
最后
以上就是花痴飞机为你收集整理的微服务:nacos配置管理&&feign远程调用&&Gateway服务网关Nacos配置管理Feign远程调用Gateway服务网关的全部内容,希望文章能够帮你解决微服务:nacos配置管理&&feign远程调用&&Gateway服务网关Nacos配置管理Feign远程调用Gateway服务网关所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复