Springcloud之openFeign

介绍

之前我们无论是基本调用,还是Hystrix,我们实际上都是通过手动调用RestTemplate来实现远程调用的。使用RestTemplate存在一个问题:繁琐,每一个请求,参数不同,请求地址不同,返回数据类型不容,其他都是一样的,所以我们希望对请求进行简化。简化方案就是openFeign。一开始这个组件不叫这个名字,一开始叫Feign,Netflix Feign,但是Netflix中的组件现在已经停止开源工作,openFeign是Springcloud团队在Netflix Feign的基础上开发出来的声明式服务调用组件。

简单使用

1.依赖
 <dependency>
   <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
 </dependency>
2.application.properties配置
spring:
  application:
    name: opentfeign
server:
  port: 4000
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka

3.启动类加@EnableFeignClients注解
@SpringBootApplication
@EnableFeignClients
public class OpenfeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(OpenfeignApplication.class, args);
    }
}
4.定义Feign服务层接口

定义接口之前在eureka-provider中添加一个方法用于测试参数放在header中传递

 @GetMapping("/user3")
    public void getUserByName(@RequestHeader String name){
        System.out.println(name);
    }

Feign服务层接口:

@FeignClient("provider") //跟某一个服务绑定
public interface HelloService {
    @GetMapping("/hello")
    String hello();

    @GetMapping("/hello2")
    String hello2(@RequestParam("name") String name);

    @PostMapping("/user2")
    User addUser(@RequestBody User user);

    @DeleteMapping("/user2/{id}")
    void deleteUserById(@PathVariable("id") Integer id);

    @GetMapping("/user3")
    void getUserByName(@RequestHeader("name") String name);
    
}

1.@FeignClient(“服务名”):跟某一个服务绑定
2.接口中的方法名可以随便写,但是映射名、返回值必须得跟对应方法保持一致
3.凡是key/value形式的参数,一定要标记参数的名称
4.放在header中的参数一定要编码之后再传递

@FeignClient注解中相关参数:

  • value/name:这两个是同一个含义,都是用配置client的服务名称
  • serviceId:已经过期,使用name即可
  • contextId:
    • 1.不想把client的多个服务(接口)定义在一个类时使用(不配置时报错):比如我们有个user服务,但user服务中有很多个接口,我们不想将所有的调用接口都定义在一个类中
    • 2.作为client别名的一部分(如果配置了@qualifier优先使用@qualifier别名)
  • fallback:熔断或发生错误兜底处理类
  • fallbackFactory:调用client发生错误兜底类
5.控制层调用接口
@RestController
public class HelloController {

    @Autowired
    HelloService helloService;

    @GetMapping("/hello")
    public String hello() throws UnsupportedEncodingException {
        String pikachues = helloService.hello2("pikachues");
        System.out.println(pikachues);

        User user = new User();
        user.setUsername("pikachues");
        user.setPassword("123");
        user.setId(99);
        User u = helloService.add2(user);
        System.out.println(u);
        helloService.deleteUser2(99);
        helloService.getUserByName(URLEncoder.encode("小明","UTF-8"));

        return helloService.hello();
    }
}
6.启动测试

继承性

从代码上看,eureka-provider提供的接口和openFeign所调用的接口几乎相同,这时我们可以将相同的部分抽取出来。
新建一个Module,叫hello-api,注意由于这个模块要被其他模块所依赖,所以这个模块是一个maven项目,但是由于这个模块要用到SpringMVC的东西,因此创建后,引入web依赖,导入SpringMVC需要的一套jar。

1.依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.4.RELEASE</version>
        </dependency>
2.定义抽取的公共接口
public interface IUserService {
    @GetMapping("/hello")
    String hello();

    @GetMapping("/hello2")
    String hello2(@RequestParam("name") String name);

    @PostMapping("/user2")
    User add2(@RequestBody User user);

    @DeleteMapping("/user2/{id}")
    void deleteUser2(@PathVariable("id") Integer id);

    @GetMapping("/user3")
    void getUserByName(@RequestHeader("name") String name);
}

3.将hello-api打包之后在eureka-provider和openfeign中引入
 <dependency>
  	<groupId>com.dpf</groupId>
     <artifactId>hello-api</artifactId>
     <version>1.0-SNAPSHOT</version>
 </dependency>
4.eureka-provider中HelloController实现该接口
@RestController
public class HelloController implements IUserService {
		.....
}
5.openfeign中的HelloService继承该接口
@FeignClient("eureka-provider")
public interface HelloService extends IUserService {

}

到这里继承就实现了,可以跟之前一样测试一下,测试效果一样。

6.优缺点分析:
  • 优点是使用继承性,可以使服务端和消费端代码统一简洁不易出错。
  • 缺点是这样会增加服务端与消费端的耦合度。

日志

OpenFeign中,我们可以通过配置日志,来查看整个请求的调用过程。日志级别一共分为四种:

  • NONE:不开启日志,默认就是这个
  • BASIC:记录请求方法、URL响应状态码、执行时间
  • HEADERS:在BASIC的基础上,加载请求/响应头
  • FULL:在HEADERS基础上,再增加body以及请求元数据
1.通过bean配置日志
@SpringBootApplication
@EnableFeignClients
public class OpenfeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(OpenfeignApplication.class, args);
    }

    @Bean
    Logger.Level loggerLevel(){
        return Logger.Level.FULL;
    }
}
2.application.yml开启日志级别
logging:
  level:
    com:
      dpf:
        openfeign:
          service:
            HelloService: debug

这里 logging.level 是指日志级别的前缀,com.dpf.openfeifn.service.HelloService,表示该类 以 debug 级别输出日志。当然,类路径也可以是一个 package ,这样就表示该 package 下的所有 class 以 debug 级别输出日志。启动调用接口可以看到如下日志。
在这里插入图片描述

数据压缩

数据的压缩,主要是解决传输效率,具体配置如下:

feign:
  compression:
    request:
      #开启请求压缩
      enabled: true
      # 压缩的数据类型      
      mime-types: text/html,application/json
      # 压缩数据的下限,2048表示当要传输的数据大于2048时,才会进行数据要锁
      min-request-size: 2048
    response:
      # 开启响应压缩
      enabled: true  

整合Hystrix

1.在配置中开启Hystrix
  hystrix:
    enabled: true
2.第一种方法
  • 定义HelloServiceFallback方法
@Component
@RequestMapping("pikachues") //防止请求地址重复
public class HelloServiceFallback implements HelloService{

    @Override
    public String hello() {
        return "error1";
    }

    @Override
    public String hello2(String name) {
        return "error2";
    }

    @Override
    public User add2(User user) {
        return null;
    }

    @Override
    public void deleteUser2(Integer id) {

    }

    @Override
    public void getUserByName(String name) {

    }
}
  • 在HelloService中的FeignClient添加fallback属性
@FeignClient(value = "eureka-provider",fallback = HelloServiceFallback.class)
public interface HelloService extends IUserService {

}
3.第二种方法
  • 定义HelloServiceFallbackFactory方法
@Component
public class HelloServiceFallbackFactory implements FallbackFactory<HelloService> {
    @Override
    public HelloService create(Throwable throwable) {
        return new HelloService() {
            @Override
            public String hello() {
                return "error1----";
            }

            @Override
            public String hello2(String name) {
                return "error2----";
            }

            @Override
            public User add2(User user) {
                return null;
            }

            @Override
            public void deleteUser2(Integer id) {

            }

            @Override
            public void getUserByName(String name) {

            }
        };
    }
}
  • 在HelloService中的FeignClient添加fallbackFactory 属性
@FeignClient(value = "eureka-provider",fallbackFactory = HelloServiceFallbackFactory.class)
public interface HelloService extends IUserService {

}

到这里整合就结束了。

项目地址

github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值