Spring Cloud-Feign 客户端

1.Feign是什么?

  在Spring Cloud Netflix栈中,每个微服务都以HTTP接口的形式暴露自身服务,因此在调用远程服务时就必须使用到HTTP客户端。我们可以使用JDK原生的URLConnection、Apache的Http Client、Netty的异步HTTP Client,还有之前我们使用到Spring的RestTemplate,这些都可以实现远程调用。
  Feign在RestTemplate的基础上对其封装,由它来帮助我们定义和实现依赖服务接口的定义。Spring Cloud Feign 基于Netflix Feign 实现的,整理Spring Cloud Ribbon 与 Spring Cloud Hystrix,并且实现了声明式的Web服务客户端定义方式。

2.Feign的基本使用

首先需要引入依赖

pom.xml

 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
     <version>1.4.3.RELEASE</version>
 </dependency>

application.yml

server:
  port: 8900
spring:
  application:
    name: consumer-order-feign
user:
  url: http://localhost:7900/user/
eureka:
  client:
    service-url:
      defaultZone:  http://user:user@localhost:8888/eureka/
然后我们来看下其他项目中提供服务这块提供的接口,和之前一样

UserController.java

package com.ithzk.spring.cloud.controller;

import com.ithzk.spring.cloud.entity.User;
import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hzk
 * @date 2018/5/13
 */
@RestController("/")
public class UserController {

    @Autowired
    private EurekaClient eurekaClient;

    @Value("${server.port}")
    private String port;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Integer id){
        return new User(id,"zs",20);
    }

    @GetMapping("/eureka/info")
    public String info(){
        //InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false);
        //return instanceInfo.getHomePageUrl()+ ":" +instanceInfo.getPort();
        return port;
    }

    @PostMapping("/get_user")
    public User getUser(User user){
        user.setName("provider_user_get_user");
        return user;
    }

}
根据提供者接口编写Feign客户端

CustomFeignClient.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * @author hzk
 * @date 2018/5/20
 */
@FeignClient("PROVIDER-USER")
public interface CustomFeignClient {

    //C版本的 spring 是不能写 GETMAPPING 的必须用RequestMapping
    @GetMapping("/user/{id}")
    User getOrder(@PathVariable("id") Integer id);

    /**
     * 如果传递复杂参数,feign默认都会以get方式去请求
     * 无法访问,提供者必须为post方式消费者才可使用,如果非要使用get传递多个数据,只能以普通方式传递
     * @param user
     * @return
     */
    @PostMapping("/get_user")
    User getUser(User user);

}

OrderController.java

package com.ithzk.spring.cloud.controller;

import com.ithzk.spring.cloud.entity.User;
import com.ithzk.spring.cloud.feign.CustomFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author hzk
 * @date 2018/5/13
 */
@RestController
public class OrderController {

    @Autowired
    private CustomFeignClient customFeignClient;

    @GetMapping("/order/{id}")
    public User getOrder(@PathVariable Integer id){
        User user = customFeignClient.getOrder(id);
        return user;
    }

    @GetMapping("/get_user")
    public User getUser(User user){
        User feignUser = customFeignClient.getUser(user);
        return feignUser;
    }
}
加上@EnableFeignClients就可以使用feign客户端,启动后成功请求获取数据,这就是feign的基本使用了

OrderApp.java

package com.ithzk.spring.cloud;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * Hello world!
 *
 */
@SpringBootApplication
@EnableFeignClients
public class OrderApp {

    //相当于xml中的bean标签 用于调用当前方法获取到指定的对象
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

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

3.Feign自定义配置

Feign客户端本身有自己默认的配置,之前学习Ribbon的时候,未指定配置时会选择Ribbon自身默认的配置,
这里也一样,Feign也可以自定义配置。

编写配置类,这里和Ribbon一样,要确保不能被主类扫描到,否则未知错误,最简单的方法依然是不放在和主类同包或子包下

MyFeignClientConfig.java

package com.ithzk.spring.config;

import feign.Contract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author hzk
 * @date 2018/5/20
 */
@Configuration
public class MyFeignClientConfig {

    /**
     * 将契约改为feign原生的默认契约。这样就可以使用feign自带的注解
     * @return
     */
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }

}
自定义客户端时指定使用配置类

CustomFeignClient.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.cloud.entity.User;
import com.ithzk.spring.config.MyFeignClientConfig;
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * @author hzk
 * @date 2018/5/20
 */
@FeignClient(name = "PROVIDER-USER",configuration = MyFeignClientConfig.class)
public interface CustomFeignClient {

    /**
     * 组合注解,第一个是请求方式,第二个是参数 用空格分割
     * 注意使用RequestLine的时候必须使用 Param 注解
     * 这里的RequestLine是feign自带注解,修改为feign默认契约后可以使用
     * @param id
     * @return
     */
    @RequestLine("GET /user/{id}")
    User getOrder(@Param("id") Integer id);

    /**
     * 如果传递复杂参数,feign默认都会以方式去请求
     * 无法访问,提供者必须为post方式消费者才可使用,如果非要使用get传递多个数据,只能以普通方式传递
     * @param user
     * @return
     */
    @RequestLine("GET /get_user")
    User getUser(User user);

}
这里通过配置自定义配置,从而达成可以使用一些Feign提供的注解

4.Feign客户端URL指定方式

上面我们通过name指定服务Feign客户端,还有一种方式可以通过指定URL去注入Feign客户端
首先我们来看一下,Eureka服务的一些信息

http://localhost:8888/eureka/apps
http://localhost:8888/eureka/apps/CONSUMER-ORDER-FEIGN
这里写图片描述
这里写图片描述

可以看出来这里面包含了注册在Eureka server上的服务的一些相关信息
我们利用Feign客户端去访问试试

CustomFeignClientTwo.java

package com.ithzk.spring.cloud.feign;

import com.ithzk.spring.config.MyFeignClientConfigTwo;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author hzk
 * @date 2018/5/20
 */
@FeignClient(name = "customfeign",url = "http://localhost:8888/",configuration = MyFeignClientConfigTwo.class)
public interface CustomFeignClientTwo {

    @RequestMapping("/eureka/apps/{servicename}")
    String getServicesName(@PathVariable("servicename") String servicename);

}

MyFeignClientConfigTwo .java

package com.ithzk.spring.config;

import feign.Contract;
import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author hzk
 * @date 2018/5/20
 */
@Configuration
public class MyFeignClientConfigTwo {

    /**
     * 用于创建用户名和密码的对象
     * @return
     */
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
        return new BasicAuthRequestInterceptor("user","user");
    }

}
如果CustomFeignClientTwo 不加上这个自定义配置,并且里面未配有用户名密码信息,则会出现权限问题无法获取数据

这里写图片描述

启动成功访问http://localhost:8900/service/info/CONSUMER-ORDER-FEIGN

这里写图片描述

5.输出日志配置

Feign本身也提供了日志输出功能,只需配置文件加一些参数,对应自定义配置中设置级别即可

application.yml

server:
  port: 8900
spring:
  application:
    name: consumer-order-feign
user:
  url: http://localhost:7900/user/
eureka:
  client:
    service-url:
      defaultZone:  http://user:user@localhost:8888/eureka/
logging:
  level:
    com.ithzk.spring.cloud.feign.CustomFeignClientTwo: debug  #给指定的 feign 设置日志输出级别,只有在 debug 的情况下才会打印日志

MyFeignClientConfigTwo .java

package com.ithzk.spring.config;

import feign.Logger;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author hzk
 * @date 2018/5/20
 */
@Configuration
public class MyFeignClientConfigTwo {

    /**
     * 用于创建用户名和密码的对象
     * @return
     */
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
        return new BasicAuthRequestInterceptor("user","user");
    }

    /**
     * 配置要输出的日志是哪些,必须在debug 模式下才可以输出
     *
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

这里写图片描述

这样很简单就配置好了日志输出

猜你喜欢

转载自blog.csdn.net/u013985664/article/details/80384445