天天看点

4_feign声明式服务调用和断路器

前言

项目准备

1、创建项目feign-consumer

2、继续使用之前的服务提供者hello-service

1、简单的声明式服务调用

1.1、pom

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

      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-feign</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">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.didispace</groupId>
   <artifactId>feign-consumer</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>feign-consumer</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.3.7.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>

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

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

   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.SR5</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>      

1.2、注解开启 spring cloud feign申明式服务调用功能

@EnableFeignClients //开启声明式服务调用

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {



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

}      

1.3、定义HelloService接口

#### 通过@FeignClient 注解指定服务名称来绑定服务 #### 然后通过springMVc 注解绑定服务提供者提供的REST接口,和服务提供者中的url是一模一样哦

@FeignClient(name="HELLO-SERVICE")
public interface HelloService {

    @RequestMapping("/hello")
    String hello();

}      

1.4、Controller 通过调用上面的接口来实现从本客户端发起对hello-service服务接口的hello的调用

//这里用来测试对feign客户端的调用
@RestController
public class ConsumerController {

    @Autowired
    HelloService helloService;

    @RequestMapping(value = "/feign-consumer", method = RequestMethod.GET)
    public String helloConsumer() {
        return helloService.hello();
    }

}      

1.5、同ribbon实现的服务消费一样,需要指定服务的注册中心

spring.application.name=feign-consumer
server.port=9001

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/      

1.6、开始验证,浏览器中访问​​http://localhost:9001/feign-consumer​​

2、参数绑定

2.1、为了验证参数绑定,再服务提供者中再添加一些方法

@RestController
public class HelloController {

   private final Logger logger = Logger.getLogger(getClass());

   @Autowired
   private DiscoveryClient client;

   @RequestMapping(value = "/hello", method = RequestMethod.GET)
   public String hello() {

      ServiceInstance instance = client.getLocalServiceInstance();
      logger.info("/hello, host:" + instance.getHost() + ", service_id:" + instance.getServiceId());
      return "Hello World";
   }



   @RequestMapping(value = "/hello1", method = RequestMethod.GET)
   String hello(@RequestParam("name") String name) {

      return "hello" +name;
   }

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

   

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


}      

2.2、在声明式服务调用的service接口中添加如下, 同时要创建和上面一模一样的User类

#### 注意点:下面注解中的value绝对不仅能为空,这是因为它和feign合作了

//绑定服务提供者,并使用spirngMvc 注解绑定具体REST接口
@FeignClient(name="HELLO-SERVICE")
public interface HelloService {

    @RequestMapping("/hello")
    String hello();


    @RequestMapping(value = "/hello1", 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);


}      

2.3、Controller 调用声明式服务传参开始吧

@RequestMapping(value = "/feign-consumer2", method = RequestMethod.GET)
public String helloConsumer2() {
    StringBuilder sb = new StringBuilder();
    sb.append(helloService.hello()).append("\n");
    sb.append(helloService.hello("DIDI")).append("\n");
    sb.append(helloService.hello("DIDI", 30)).append("\n");
    sb.append(helloService.hello(new User("DIDI", 30))).append("\n");
    return sb.toString();
}      

2.4、开始验证,浏览器中访问

4_feign声明式服务调用和断路器

3、继承特性,解决User不同位置的问题

解释:

1、这个时候我们会发现,在声明式服务中的User和服务提供者中的User的内容一抹一样,但是位置却不是一样的,所以这样很不利于维护,因为修改了一处,还要继续去修改另外的一处。
2、在声明式@FeginClient中提供的接口其实服务提供者也可以使用。所以,请看下面

3.1、创建一个maven项目 hello-service-api

3.1.1 、pom.xml如下

<?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">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.didispace</groupId>
   <artifactId>hello-service-api</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>hello-service-api</name>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.3.7.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
   </dependencies>

</project>      

3.1.2、将2中的User复制过来

4_feign声明式服务调用和断路器

3.1.3、将声明式服务调用中的接口类HelloService 复制过来,还要做一番修改哦

1、将头部前缀修改为refactor
2、url路径也修改更名为hello4 5 6
@RequestMapping("/refactor")
public interface HelloService {

    @RequestMapping(value = "/hello4", method = RequestMethod.GET)
    String hello(@RequestParam("name") String name) ;

    @RequestMapping(value = "/hello5", method = RequestMethod.GET)
    User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age);

    @RequestMapping(value = "/hello6", method = RequestMethod.POST)
    String hello(@RequestBody User user);

}      

3.2、开始对服务提供者进行重构

3.2.1、在hellop-service项目pom.xml中引入hello-service-api的依赖,一定要记得对它进行mvn install

<dependency>
   <groupId>com.didispace</groupId>
   <artifactId>hello-service-api</artifactId>
   <version>0.0.1-SNAPSHOT</version>
</dependency>      

3.2.2、2、重点来了,创建controller类基础上面的HelloService,没有必要在加@RequestMapping,但是其他的是一定要加的

@RestController
public class RefactorHelloController implements HelloService{


    public String hello(@RequestParam("name") String name) {

        return "hello" +name;
    }

    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age){
        return  new User(name,age);
    }
    

    public String hello(@RequestBody User user){
        return "hello"+user.getName()+","+user.getAge();
    }

}      

3.3、下面开始对声明式服务调用开始改造

3.3.1、引入pom依赖

<dependency>
   <groupId>com.didispace</groupId>
   <artifactId>hello-service-api</artifactId>
   <version>0.0.1-SNAPSHOT</version>
</dependency>      

3.3.2、绑定服务提供者,接口让他来继承HelloService,这样就保证了和服务提供者中的R EST是一致的了

//绑定服务提供者
@FeignClient(name="HELLO-SERVICE")
public interface RefactorHelloService  extends HelloService {

}      

3.3.3、Controller开测

//这里用来测试对feign客户端的调用
@RestController
public class ConsumerController {

    @Autowired
    RefactorHelloService refactorHelloService;

    /**
     *  2、测试传参
     */

    @RequestMapping(value = "/feign-consumer2", method = RequestMethod.GET)
    public String helloConsumer2() {
        StringBuilder sb = new StringBuilder();
        sb.append(refactorHelloService.hello("DIDI")).append("\n");
        sb.append(refactorHelloService.hello("DIDI", 30)).append("\n");
        sb.append(refactorHelloService.hello(new User("DIDI", 30))).append("\n");
        return sb.toString();
    }
}      

3.3.4、开始测试,浏览器访问 http://localhost:9001/feign-consumer2 成功

4_feign声明式服务调用和断路器

4、服务降级配置,类似于断路器(使用3中的项目开发)

4.1、声明式服务调用项目中添加service

HelloServiceFallback,使它实现HelloService 用来作为当调用服务提供者失败后返回的内容

@Component
public class HelloServiceFallback implements HelloService {


    @Override
    public String hello(@RequestParam("name") String name) {
        return "error";
    }

    @Override
    public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
        return new User("未知", 0);
    }

    @Override
    public String hello(@RequestBody User user) {
        return "error";
    }
}      

4.2、@Feign 绑定服务的时候就开始,添加降级配置

//绑定服务提供者,并使用spirngMvc 注解绑定具体REST接口
@FeignClient(name="HELLO-SERVICE" ,fallback =HelloServiceFallBack.class )
public interface HelloService {

    @RequestMapping("/hello")
    String hello();

    @RequestMapping(value = "/hello1", 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);


}      

4.3、浏览器测试(不开启服务提供者) http://localhost:9001/feign-consumer2

​​HealerJean-代码下载​​