SpringCloud实战5-Feign声明式服务调用

简介: 在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。

Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。

而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

总起来说,Feign具有如下特性:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP编码器和解码器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的负载均衡;
  • 支持HTTP请求和响应的压缩。

这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。这种模式是我们非常喜欢的。Feign是用@FeignClient来映射服务的。

 

首先第一步,在原来的基础上新建一个Feign模块,接着引入相关依赖,引入Feign依赖,会自动引入Hystrix依赖的,如下:

    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.3.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.0.RELEASE</version>
        </dependency>

 

application.yml配置如下:

server:
  port: 8083
spring:
  application:
    name: feign-consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

 

 

接着在前面文章中的的的两个provider1和provider2两个模块的服务新增几个方法,如下代码所示:

/**
 * Created by cong on 2018/5/8.
 */
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("访问来1了......");
        return "hello1";
    }

    @RequestMapping("/hjcs")
    public List<String> laowangs(String ids){
        List<String> list = new ArrayList<>();
        list.add("laowang1");
        list.add("laowang2");
        list.add("laowang3");
        return list;
    }

    //新增的方法
    @RequestMapping(value = "/hellol", method= RequestMethod.GET)
    public String hello(@RequestParam String name) {
        return "Hello " + name;
    }

    @RequestMapping(value = "/hello2", method= RequestMethod.GET)
    public User hello(@RequestHeader String name, @RequestHeader Integer age) {
        return new User(name, age);
    }

    @RequestMapping(value = "/hello3", method = RequestMethod.POST)
    public String hello (@RequestBody User user) {
        return "Hello "+ user. getName () + ", " + user. getAge ();
    }

}

 

接着是上面代码所需用到的User类,代码如下:

/**
 * Created by cong 2017/12/2.
 */
public class User {

    private String name;
    private Integer age;

    //序列化传输的时候必须要有空构造方法,不然会出错
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

 

接下来用Feign的@FeignClient(“服务名称”)映射服务调用。代码如下:

package hjc;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;

/**
 * Created by cong on 2018/5/17.
 */
//configuration = xxx.class  这个类配置Hystrix的一些精确属性
//value=“你用到的服务名称”
@FeignClient(value = "hello-service",fallback = FeignFallBack.class) public interface FeignService {   //服务中方法的映射路径 @RequestMapping("/hello") String hello(); @RequestMapping(value = "/hellol", method= RequestMethod.GET) String hello(@RequestParam("name") String name) ; @RequestMapping(value = "/hello2", method= RequestMethod.GET) User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age); @RequestMapping(value = "/hello3", method= RequestMethod.POST) String hello(@RequestBody User user); }

 

接着在Controller层注入FeiService这个接口,进行远程服务调用,代码如下:

/**
 * Created by cong on 2018/5/17.
 */
@RestController
public class ConsumerController {

    @Autowired
    FeignService feignService;

    @RequestMapping("/consumer")
    public String helloConsumer(){
        return feignService.hello();
    }

    @RequestMapping("/consumer2")
    public String helloConsumer2(){
        String r1 = feignService.hello("hjc");
        String r2 = feignService.hello("hjc", 23).toString();
        String r3 = feignService.hello(new User("hjc", 23));
        return r1 + "-----" + r2 + "----" + r3;
    }

}

 

接着在Feign模块的启动类哪里打上Eureka客户端的注解@EnableDiscoveryClient  Feign客户端的注解@EnableFeignClients,代码如下:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {

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

 

接着启动启动类,浏览器上输入localhost:8083/consumer  运行结果如下:

 

可以看到负载均衡轮询出现hello1,hello2。

 

接着继续在浏览器上输入localhost:8083/consumer2,运行结果如下:

 

 

接下来我们进行Feign声明式调用服务下的,服务降级的使用,那么我们就必须新建一个FeignFallBack类来继承FeiService,代码如下:

package hjc;

import org.springframework.stereotype.Component;

/**
 * Created by cong on 2018/5/17.
 */
@Component
public class FeignFallBack implements FeignService{
  //实现的方法是服务调用的降级方法 @Override
public String hello() { return "error"; } @Override public String hello(String name) { return "error"; } @Override public User hello(String name, Integer age) { return new User(); } @Override public String hello(User user) { return "error"; } }

 接着我们再把那两个服务提供模块provider1,provider2模块进行停止,运行结果如下所示:

 

 可以看到我们这几个调用,都进行了服务降级了。

 

那么如果我们想精确的控制一下Hystrix的参数也是可以的,比方说跟Hystrix结合的参数,那么可以在FeignClient注解里面配置一个Configuration=XXX类.class属性,在哪个类里面精确的指定一下属性。

或者在application.yml里面配置,如下:

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutinMilliseconds: 5000

ribbon:
  connectTimeout: 500

#如果想对单独的某个服务进行详细配置,如下
hello-service:
  ribbon:
    connectTimeout: 500

 

这里满足了我们大部分场景的调用,但是有写精细场景,还是要用原生的Hystrix,跟我们之前的Hystrix用法一下,不要走Feign客户端调用就行了,如下:

/**
 * Created by cong on 2018/5/17.
 */
public class HjcCommand extends HystrixCommand {
    protected HjcCommand(HystrixCommandGroupKey group) {
        super(group);
    }

    @Override
    protected Object run() throws Exception {
        return null;
    }
}

 

那么我们如果想用原声的HystrixCommand去搞一个异步请求怎么办?代码如下:

首先再引入一个依赖,feign客户端没有默认引入进来,需要我们自己引入:

    <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.9</version>
        </dependency>

接着用HystrixCommand注解方式实现:

/**
 * Created by cong on 2018/5/17.
 */
@Service
public class HjcCommand {

    @Autowired
    private FeignService feignService;

    //同步方式
    @HystrixCommand
    public Future<String> getEmployeesAsync(){
        return new AsyncResult<String>() {
            @Override
            public String invoke() {
                return feignService.hello("hjc");
            }
        };
    }

    //用同步方式还不如直接用Feign客户端
    @HystrixCommand
    public String getEmployeesAsync1(){
        return feignService.hello("laowang");
    }

}

这样还不行,我们还需要声明一个切面,HystrixConfiguration,接着,将HystrixConfiguration加入到spring管理,代码如下:

@Configuration
public class HystrixConfiguration {

    @Bean
    public HystrixCommandAspect hystrixAspect(){
        return  new HystrixCommandAspect();
    }

}

 

目录
相关文章
|
27天前
|
JSON Java 测试技术
SpringCloud2023实战之接口服务测试工具SpringBootTest
SpringBootTest同时集成了JUnit Jupiter、AssertJ、Hamcrest测试辅助库,使得更容易编写但愿测试代码。
55 3
|
2月前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
180 6
|
2月前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
108 2
|
2月前
|
JSON Java 数据格式
【微服务】SpringCloud之Feign远程调用
本文介绍了使用Feign作为HTTP客户端替代RestTemplate进行远程调用的优势及具体使用方法。Feign通过声明式接口简化了HTTP请求的发送,提高了代码的可读性和维护性。文章详细描述了Feign的搭建步骤,包括引入依赖、添加注解、编写FeignClient接口和调用代码,并提供了自定义配置的示例,如修改日志级别等。
110 1
|
2月前
|
Java 数据库连接 Spring
【2021Spring编程实战笔记】Spring开发分享~(下)
【2021Spring编程实战笔记】Spring开发分享~(下)
31 1
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
3月前
|
前端开发 API 微服务
SpringCloud微服务之间使用Feign调用不通情况举例
SpringCloud微服务之间使用Feign调用不通情况举例
628 2
|
2月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
76 0
|
2月前
|
XML Java 数据库连接
【2020Spring编程实战笔记】Spring开发分享~(上)
【2020Spring编程实战笔记】Spring开发分享~
55 0
|
3月前
|
Java API 开发者
【已解决】Spring Cloud Feign 上传文件,提示:the request was rejected because no multipart boundary was found的问题
【已解决】Spring Cloud Feign 上传文件,提示:the request was rejected because no multipart boundary was found的问题
608 0