上次回归:
上次我们说了 ribbon 的基本使用, 包括里面的内部算法, 算法的细粒度配置, 还有我们自己如何实现我们自己的算法, 主要还是一些基本使用的知识, 还不会使用 ribbon 的小伙伴可以回去看一下上一篇博客.
什么是 Feign:
Feign 是 Netflix 开发的声明式, 模板化的 HTTP 客户端, 其灵感来自 Retrofit,JAXRS2.0 以及 webSocket.Feign 可帮助我们更加便捷, 优雅地调用 HTTP API, 为什么我们会选择使用 Feign 呢? 我们上次说到的 ribbon 也是可以调用远程 API 的啊, 但是你的请求地址参数很多呢? 比如这样, 而且参数还总是变化的 (客户每天都在变需求), 你每次都需要改写代码, 地址太长还容易写错, 是不是觉得写起来很吃力的样子, 我们这次学习的 Feign 就是来解决这个问题的.
Feign 的常用配置详解:
刚才我们简单的说到了 Feign 是做什么的, 我们来看一下, 我们如何使用 Feign 吧. 还是我们的两个服务, 一个用户服务, 一个订单服务, 我们分别来看一下配置.
一, 最简单的启动
1. 首先加入父依赖包, 在启动类加入注解 @EnableFeignClients
- <!-- 加入 Feign 依赖 -->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- package com.xiaocaiFeign;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
- import org.springframework.cloud.openfeign.EnableFeignClients;
- @SpringBootApplication
- @EnableFeignClients
- @EnableDiscoveryClient
- public class FeignOrderApplication {
- public static void main(String[] args) {
- SpringApplication.run(FeignOrderApplication.class, args);
- }
- }
2. 创建我们的订单服务, 建立一个接口, 接口如下, 需要加注解 @FeignClient(name = "feign-order"), 实现类你们自己去完成吧
- package com.xiaocaiFeign.controller;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.Web.bind.annotation.PathVariable;
- import org.springframework.Web.bind.annotation.RequestMapping;
- @FeignClient(name = "feign-order")
- public interface OrderController {
- @RequestMapping("/getOrderData/{orderId}")
- String getOrderData(@PathVariable("orderId") String orderId);
- }
3. 修改我们的订单服务的 POM 文件, 弄成一个 jar 包即可, 不需要可执行的 jar 包.
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
4. 创建我们的用户服务, 将我们的订单服务以 jar 包的形式引入进来.
- <dependencies>
- <dependency>
- <groupId>com</groupId>
- <artifactId>feignOrder</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- </dependencies>
这里千万注意一个问题, 你的订单服务和你的用户服务, 包路径一定要相同, 不然 springboot 是扫描不到你的包的, 切记~!!!
5. 编写我们的调用类 (用户服务)
- package com.xiaocaiFeign.controller;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.RestController;
- @RestController
- public class UserController {
- @Autowired
- private OrderController orderController;
- @GetMapping("/getOrder")
- public String getOrderData() {
- System.out.println("准备调用");
- String orderData = orderController.getOrderData("1");
- System.out.println(orderData);
- return orderData;
- }
- }
运行看结果
是不是超级简单.
二, 打印日志级别
首先我们在订单服务加入一个配置, 千万别写 @Configuration
- package com.xiaocaiFeign.config;
- import feign.Logger;
- import org.springframework.context.annotation.Bean;
- public class FeignLogConfig {
- @Bean
- public Logger.Level level() {
- //return Logger.Level.NONE; //(默认) 不打印任何日志
- return Logger.Level.BASIC;// 仅记录请求方法, URL, 响应状态代码以及执行时间, 生成一般用这个
- //return Logger.Level.HEADERS;// 在 BASIC 基础之上还记录了请求和响应的 header.
- //return Logger.Level.FULL;// 记录了请求和响应的 header,body 和元数据
- }
- }
然后在我们的接口类下面给予这个配置
- package com.xiaocaiFeign.controller;
- import com.xiaocaiFeign.config.FeignLogConfig;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.Web.bind.annotation.PathVariable;
- import org.springframework.Web.bind.annotation.RequestMapping;
- @FeignClient(name = "feign-order", configuration = FeignLogConfig.class)
- public interface OrderController {
- @RequestMapping("/getOrderData/{orderId}")
- String getOrderData(@PathVariable("orderId") String orderId);
- }
最后我们在我们的用户服务中开启配置, 注意 xiaocaiFeign 是你的包名.
- logging:
- level:
- com:
- xiaocaiFeign: debug
我们来看一下效果, 我这只演示一下 FULL 的吧~!
三, 额外我觉得没用的配置, 契约配置
反正我是觉得没啥大用, 而且还不熟悉的, 和我们的日志差不多, 加入一个自定义的配置类
- package com.xiaocaiFeign.config;
- import feign.Contract;
- import org.springframework.context.annotation.Bean;
- public class MyFeignConfig {
- /**
- * 根据 SpringBoot 自动装配 FeignClientsConfiguration 的 FeignClient 的契约是 SpringMvc
- * 通过修改契约为默认的 Feign 的锲约, 那么就可以使用默认的注解
- * @return
- */
- @Bean
- public Contract feiContract() {
- return new Contract.Default();
- }
- }
然后通过接口引入, 但是这回接口必须要写 feign 的注解了, 我觉得没这个必要, 我还是比较习惯用 springMVC 的注解.
- package com.xiaocaiFeign.controller;
- import com.xiaocaiFeign.config.MyFeignConfig;
- import feign.Param;
- import feign.RequestLine;
- import org.springframework.cloud.openfeign.FeignClient;
- @FeignClient(name = "feign-order", configuration = MyFeignConfig.class)
- public interface OrderController {
- @RequestLine("GET /getOrderData/{orderId}")
- String getOrderData(@Param("orderId") String orderId);
- }
这写就可以调用了, 里面都别写错了, 写错了, 用户服务可能会启动失败的.
四, 请求头传递
最后一个实例了, 假如我们这样的, 用户服务调用订单服务, 订单服务每次调用需要携带请求头 token 进行验证, 我们又该如何来做呢? 我们来看一下代码实现, 先弄一个拦截器.
- package com.xiaocaiFeign.config;
- import feign.RequestInterceptor;
- import feign.RequestTemplate;
- import org.springframework.Web.context.request.RequestContextHolder;
- import org.springframework.Web.context.request.ServletRequestAttributes;
- import javax.servlet.http.HttpServletRequest;
- public class MyRequestInterceptor implements RequestInterceptor {
- @Override
- public void apply(RequestTemplate template) {
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = attributes.getRequest();
- template.header("token", request.getHeader("token"));
- }
- }
然后将拦截器配置到 Feign 下面去.
- package com.xiaocaiFeign.controller;
- import com.xiaocaiFeign.config.FeignLogConfig;
- import com.xiaocaiFeign.config.MyFeignConfig;
- import com.xiaocaiFeign.config.MyRequestInterceptor;
- import feign.Param;
- import feign.RequestLine;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.Web.bind.annotation.PathVariable;
- import org.springframework.Web.bind.annotation.RequestMapping;
- @FeignClient(name = "feign-order",configuration = MyRequestInterceptor.class)
- public interface OrderController {
- @RequestMapping("/getOrderData/{orderId}")
- String getOrderData(@PathVariable("orderId") String orderId);
- // @RequestLine("GET /getOrderData/{orderId}")
- // String getOrderData(@Param("orderId") String orderId);
- @RequestMapping("/getOrderToken")
- String getOrderToken();
- }
自己去测试一下调用结果吧, 我弄这个弄了好久, 保证没问题的, 我就不上图了.
Feign 的优化配置:
我们的 Feign 底层还是使用 Ribbon 来调用的, 第一次很多时候会调用的慢, 我可以改为 HTTPClient 调用方式.
- feign:
- client:
- config:
- connectTimeout: 5000 #连接超时时间 (毫秒)
- readTimeout: 5000 # 读取超时时间 (毫秒)
- product-center:
- loggerLevel: full # 日志级别
- contract: feign.Contract.Default #指定默认契约
- httpclient:
- enabled: true # 开启 httpClient
- max-connections: 200 # 最大连接数
- max-connections-per-route: 50 # 为每个 url 请求设置最大连接数
nacos 配置中心详解:
nacos 里面还有一个配置中心还没有去说, 我们现在的项目很多都是微服务的, 也知道微服务会拆分成很多个小的服务, 加入你拆分的不多, 10 个服务, 本地开发环境, 公共开发环境, 测试环境, 生产环境, 那么你就意味着你需要弄 40 个配置文件, 而且你会暴露你的数据库地址给开发, 那么我们这次就用 nacos 来看看配置中心是如何做的吧. 我们先弄一个最简单的测试类.
- package com.nacosConfig.controller;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.RestController;
- @RestController
- public class ConfigCenterController {
- @Value("${config.center.name}")
- private String name;
- @GetMapping("/")
- public String getData() {
- System.out.println(name);
- return name;
- }
- }
- server:
- port: 8080
- config:
- center:
- name: "张三"
先不用 nacos 配置中心, 我们来测试一下.
我们来看一下 nacos 是怎么来配置的
1. 加入依赖包.
- <!-- 引入 nacos 配置依赖 -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-alibaba-nacos-config</artifactId>
- </dependency>
2. 新建一个叫做 Bootstrap.YAML 的配置, 这个配置会优先于 springboot 自带的 application.YAML 配置.
- spring:
- application:
- name: nacos
- profiles:
- active: config
- cloud:
- nacos:
- config:
- server-addr: 192.168.138.119:8848
- namespace: 83cbe7a9-7713-4d5c-b052-a42ba1df9e84
- file-extension: YAML
来解释一下我们的配置, 第一个 spring.application.name=nacos 是我们的文件名字, spring.profiles.active=config 还是我们的文件名字, spring.cloud.nacos.config.file-extension=YAML 是文件后缀, 就是说, 我们会去拿名字为 nacos-config.YAML 这个文件. 连接和命令空间这里就不说了, 在 nacos 的注册中心讲的已经很详细了.
3. 登录 nacos 页面, 点击配置列表, 选择对应的命名空间, 点击 "+" 进行新增.
就这样, 一个简单的配置中心就完成了 (启动会报错, 是因为你的注册中心没有注册成功报错的). 而且还可以查看历史版本, 用起来还是不错的, 你可以在 application.YAML 写入你的注册配置, 如下所示
- spring:
- application:
- name: nacos-config
- cloud:
- nacos:
- discovery:
- server-addr: 192.168.138.119:8848
这时项目启动的时候会自动拉取 nacos-config.YAML 配置文件. 这样写是什么意思呢? 就是你一个 shoppingServer, 你有不同的环境, 我们写一个通用的配置 shoppingServer.YAML, 然后通过你的 shoppingServer-dev.YAML,shoppingServer-st.YAML, 等文件来细化咱们的不同环境的配置.
还有一个配置是这样的.
- spring:
- application:
- name: nacos-config
- profiles:
- active: dev
- cloud:
- nacos:
- config:
- server-addr: 192.168.138.119:8848
- file-extension: YAML
- shared-dataids: config1.YAML,config2.YAML
就是说我们还有加载 config1.YAML 和 config2.YAML 配置文件. 现在我们说到四个配置文件了, 那么他们的顺序又是什么呢? config1.YAML<<<config2.YAML<<<nacos-config.YAML<<<nacos-config-dev.YAML, 越是在后面加载的, 权利越大, 就是后面的配置可以覆盖掉前面的配置. 这里的 shared-dataids: config1.YAML,config2.YAML 一般用于不同系统中的通用配置, 比如我们在用户系统和订单系统有通用配置, 我们可以通过 shared-dataids 的方式来引入配置.
还可以这样来写
- spring:
- application:
- name: nacos-config
- profiles:
- active: dev
- cloud:
- nacos:
- config:
- server-addr: 192.168.138.119:8848
- file-extension: YAML
- shared-dataids: config1.YAML,config2.YAML
- refreshable-dataids: config1.YAML,config2.YAML
- ext-config:
- - data-id: config3.YAML
- group: DEFAULT_GROUP
- refresh: true
- - data-id: config4.YAML
- group: DEFAULT_GROUP
- refresh: true
这回又多了一些文件, 顺序是什么样子的呢? 我再来写一下 config1.YAML<<<config2.YAML<<<config3.YAML<<<config4.YAML<<<nacos-config.YAML<<<nacos-config-dev.YAML.
- spring:
- application:
- name: nacos-config
- profiles:
- active: dev
- cloud:
- refresh:
- enabled: true # 默认是 true
- nacos:
- config:
- server-addr: 192.168.138.119:8848
- file-extension: YAML
- shared-dataids: config1.YAML,config2.YAML
- refreshable-dataids: config1.YAML,config2.YAML
- ext-config:
- - data-id: config3.YAML
- group: DEFAULT_GROUP
- refresh: true
- - data-id: config4.YAML
- group: DEFAULT_GROUP
- refresh: false
其中标红的那个几个值是控制是否可以动态刷新的, 就是说我们改了配置中心的配置, 不用重启服务, 配置就可以生效的, 需要在类上面加入 @RefreshScope 注解.
最后一个问题, nacos 改密码和添加账户, 我们集群的时候连接一个 MySQL 数据库对吧, 单机的比较头疼, 我们设置单机的内部是用一个 Derby 这个数据库来连接的, 我这里只能用 IDEA 改本地的 Derby 然后拷贝到 Linux 上去, 暂时没啥别的好办法, 用页面也能改, 但是无法添加用户, 而我们的集群是用的 MySQL, 我们可以自己操作啦, 来一个添加用户的操作, 打开我们的 MySQL 的 nacos 库, 找到 users 表, 添加用户, 然后我们用下面的方法来手动生成密码.
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-security</artifactId>
- <version>1.2.2.RELEASE</version>
- </dependency>
- public static void main(String[] args) {
- String nacos = new BCryptPasswordEncoder().encode("nacos");
- System.out.println("nacos =" + nacos);
- }
然后把我们的密码自己弄到 MySQL 数据库内就可以啦
总结:
这次主要说了 feign 的基本使用, 日志级别的选择, 还有我们的请求头如何传递, 然后就是我们的 Nacos 的配置中心是如何去做的, 我们配置文件的加载顺序, 最后是我们的 nacos 如何添加用户和修改密码 (页面就可以改).
最进弄了一个公众号, 小菜技术, 欢迎大家的加入
来源: https://www.cnblogs.com/cxiaocai/p/12291082.html