Feign的配置和使用

目录

RestTemplate方式调用存在的问题:

定义和使用Feign客户端

自定义Feign的配置

性能优化

Feign的最佳实践

Feign的使用步骤:

1、引入依赖
2、添加@EnableFeignClients注解

3、编写FeignClient接口
4、使用FeignClient中定义的方法代替RestTemplate


Feign的日志配置:
1、方式一是配置文件,feign.client.config.xxx.loggerLevel
①如果xxx是default则代表全局
②如果xxx是服务名称,例如userservice则代表某服务

2、方式二是java代码配置Logger.Level这个Bean
①如果在@EnableFeignClients注解声明则代表全局

②如果在@FeignClient注解中声明则代表某服务


Feign的优化:命
1、日志级别尽量用basic
2、使用Httpclient或OKHttp代替URLConnection
        引入feign-httpClient依赖
        配置文件开启httpClient功能,设置连接池参数


Feign的最佳实践:
1、让controller和FeignClient继承同一接口
2、将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用


不同包的FeignClient的导入有两种方式:
1、在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包
2、在@EnableFeignClients注解中添加clients,指定具体Feignclient的字节码
 

RestTemplate方式调用存在的问题:

string url = "http: //userservice/user/" + order.getUserId();

User user = restTemplate.getFor0bject(url,User.class);

存在下面的问题:
代码可读性差,编程体验不统一
参数复杂URL难以维护

定义和使用Feign客户端

1.引入依赖:

在orderservice的pom文件引入依赖

<!--feign客户端依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<?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>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户依赖-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->
        <!-- nacos客户端依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.在order-service的启动类添加注解开启Feign的功能:

在orderservice的启动类中添加注解

@EnableFeignClients
package cn.itcast.order;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
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.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    //创建RestTemplate并注入Spring容器
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

//    @Bean
//    public IRule randomRule(){
//        return new RandomRule();//将负载均衡设置为随机,范围为整个order
//    }
}

3.编写Feign客户端:

添加一个包,并写一个接口,再引入客户端注解FeignClient

package cn.itcast.order.clients;

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);
}

4、改造orderservice的service.java文件,把以前写的RestTemplate方式换成Feign方式

package cn.itcast.order.service;

import cn.itcast.order.clients.UserClient;
import cn.itcast.order.mapper.OrderMapper;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        // 2.1.url路径
        User user = userClient.findById(order.getUserId());
        // 3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }

//    @Autowired
//    private RestTemplate restTemplate;
//
//    public Order queryOrderById(Long orderId) {
//        // 1.查询订单
//        Order order = orderMapper.findById(orderId);
//        // 2.利用RestTemplate发送http请求,查询用户
//        // 2.1.url路径
//        String url = "http://userservice/user/" + order.getUserId();
//        // 2.2.发送http请求,实现远程调用
//        User user = restTemplate.getForObject(url, User.class);//第一个参数是路径,第二个参数是返回的类=类型
//        // 3.封装user到order
//        order.setUser(user);
//        // 4.返回
//        return order;
//    }
}

访问数据,可以发现:两个userservice都能访问,并且是负载均衡

自定义Feign的配置

方式一:配置文件方式,在orderservice的application.yml文件添加
1、全局生效:

feign:
  client:
    config:
      default: #这里填default是全局生效,填服务名就是局部生效
        loggerLevel: FULL #显示完整信息
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
#      discovery:
#        cluster-name: HZ #集群名称
#        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
feign:
  client:
    config:
      default: #这里填default是全局生效,填服务名就是局部生效
        loggerLevel: FULL  #显示完整信息

 可以看到只是访问一次数据,就有很多信息

2、局部生效: 

feign:
  client:
    config:
      userservice: #这里填default是全局生效,填服务名就是局部生效
        loggerLevel: FULL #显示完整信息

方式二: java代码方式,需要先声明一个Bean:

先把方式一的代码注释掉

#feign:
#  client:
#    config:
#      default: #这里填default是全局生效,填服务名就是局部生效
#        loggerLevel: FULL #显示完整信息

server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
#      discovery:
#        cluster-name: HZ #集群名称
#        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
#feign:
#  client:
#    config:
#      default: #这里填default是全局生效,填服务名就是局部生效
#        loggerLevel: FULL #显示完整信息

先添加一个包config,再添加一个DefaultFeignConfiguration.java

 
package cn.itcast.order.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;

public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.BASIC;
    }
}

1、如果是全局配置,则把它放到@EnableFeignClients这个注解中:

@EnableFeignClients(defaultConfiguration = FeignclientConfiguration.class)

添加在启动类上:

package cn.itcast.order;

import cn.itcast.order.config.DefaultFeignConfiguration;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
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.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    //创建RestTemplate并注入Spring容器
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

//    @Bean
//    public IRule randomRule(){
//        return new RandomRule();//将负载均衡设置为随机,范围为整个order
//    }
}

请求数据,可以看到比起方式一,这种方式的信息简洁许多。因为第一种方式用的FULL,而第二种方式是BASIC

2、如果是局部配置,则把它放到@FeignClient这个注解中:

@FeignClient(value = "userservice", configuration = FeignClientConfiguration.class) 

添加在UserClient.interface上,这里就不再做演示了。

性能优化

Feign添加HttpClient的支持:

引入依赖

<!--引入httpClient依赖-->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池

feign:
  httpclient:
    enabled: true #支持httpclient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个请求路径的最大连接数
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
    username: root
    password: 1234
    driver-class-name: com.mysql.jdbc.Driver
  application:
    name: orderservice #order的微服务名称
  cloud:
    nacos:
      server-addr: localhost:8848
#      discovery:
#        cluster-name: HZ #集群名称
#        namespace: 8279562b-ce89-420a-b765-f8b2adfdbe49 #命名空间id
#        ephemeral: false #是否为临时实例
mybatis:
  type-aliases-package: cn.itcast.user.pojo
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    cn.itcast: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
#eureka:
#  client:
#    service-url: #eureka地址信息1
#      defaultZone: http://127.0.0.1:10086/eureka
userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule #负载均衡规则:随机。范围:userservice服务
ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients:  #指定饥饿加载的服务
      - userservice
feign:
  httpclient:
    enabled: true #支持httpclient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个请求路径的最大连接数

Feign的最佳实践

方式一(继承)︰给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。

方式二(抽取)︰将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用

这里我只实现方式二

1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖

<!--引入feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<?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>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feign-api</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

</project>

2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都剪切到feign-api项目中

因为这些代码移到其他模块了,所以会报错

①UserClient的User报错,重新导包,用feign包内的User

②Orderservice的Order依赖User报错,在pom文件引入依赖,并重新导包,用feign模块的包

<!--引入feign的统一依赖-->
<dependency>
    <groupId>cn.itcast.demo</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0</version>
</dependency>
<?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>cloud-demo</artifactId>
        <groupId>cn.itcast.demo</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--eureka客户依赖-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--        </dependency>-->
        <!-- nacos客户端依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--feign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--引入httpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
        <!--引入feign的统一依赖-->
        <dependency>
            <groupId>cn.itcast.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

③Orderservice的Orderservice报错,重新导入feign模块下的包

④Orderservice的启动类报错,导入feign模块的包

⑤当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。

有两种方式解决:

方式一:指定FeignClient所在包

@EnableFeignclients(basePackages = "cn.itcast.feign.clients")

方式二:指定Feignclient字节码

@EnableFeignclients(clients = {Userclient.class}) 

在order的启动类的EnableFeignclients加一个属性

@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)

我这里使用第一个方式 

package cn.itcast.order;

import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.config.DefaultFeignConfiguration;
import org.mybatis.spring.annotation.MapperScan;
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.web.client.RestTemplate;

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

    //创建RestTemplate并注入Spring容器
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

//    @Bean
//    public IRule randomRule(){
//        return new RandomRule();//将负载均衡设置为随机,范围为整个order
//    }
}

访问数据,请求成功
代码文件点击下载icon-default.png?t=N7T8https://pan.baidu.com/s/1GooYipFzcnCyubANjf5S6Q?pwd=vpea上一篇:Nacos配置管理

下一篇:Gateway的配置和使用

  • 21
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用Feign进行服务之间的调用时,可以通过配置开启Hystrix的熔断功能。如果服务不可用或者超过访问时间,就会触发Hystrix的fallback回调函数。要开启熔断配置,需要在服务消费者的pom文件中添加Hystrix的依赖。然后创建Feign的实现类,实现Feign中的方法,并在Feign接口的@FeignClient注解中加上fallback属性,值是Feign实现类的字节码文件。在主启动类上加上@EnableHystrix注解来允许Hystrix的使用。在配置文件中设置开启熔断功能,可以通过feign.hystrix.enabled=true来开启Feign的熔断功能。\[1\] Feign中的Hystrix配置如下: ``` feign: hystrix: enabled: true okhttp: enabled: true httpclient: enabled: false client: config: default: # 超时时间配置 connectTimeout: 10000 readTimeout: 10000 compression: request: enabled: true response: enabled: true # Hystrix配置 hystrix: command: default: execution: isolation: strategy: SEMAPHORE thread: timeoutInMilliseconds: 60000 shareSecurityContext: true ``` 以上是Feign中Hystrix的配置,可以根据实际需求进行相应的调整。\[3\] #### 引用[.reference_title] - *1* *3* [Spring Cloud Feign熔断配置](https://blog.csdn.net/Diandikongji/article/details/112747687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [feign的熔断](https://blog.csdn.net/weixin_45893072/article/details/122972939)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@katoumegumi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值