SpringCloud2.x(四)声明式REST调用——Feign

在服务提供者项目microservice-provider增加一个带参数的接口

        @GetMapping("/pay_with_params")
	public String pay(String orderCode, int totalPrice) {
		return "支付成功-->订单编号:" + orderCode + ",金额:" + totalPrice;
	}

然后,在服务消费者里面是这么调用的

        @GetMapping("/order/without_feign_pay")
	public String withoutFeignPay() {
		String orderCode = UUID.randomUUID().toString();
		int totalPrice = 100;
		return restTemplate.getForObject("http://provider-pay/pay_with_params?orderCode=" + orderCode
				+ "&totalPrice=" + totalPrice, String.class);
	}

或者是这么调用的

        @GetMapping("/order/without_feign_pay2")
	public String withoutFeignPay2() {
		Map paramMap = new HashMap<>();
		paramMap.put("orderCode", UUID.randomUUID().toString());
		paramMap.put("totalPrice", 200);
		
		return restTemplate.getForObject("http://provider-pay/pay_with_params?orderCode={orderCode}&"
				+ "totalPrice={totalPrice}", String.class, paramMap);
	}

不管哪一种,在参数多了的情况下,代码就会变得难以维护。这时候,Feign是解决这个问题的利器。

一、Feign简介

Feign是Netflix开发的声明式、模块化的HTTP客户端,可以帮助我们更加便捷、优雅地调用HTTP API。

Spring Cloud对Feign进行了增强,使Feign除了可以使用自带的注解或者JAX-RS注解以外,还支持了Spring MVC注解,并整合了Ribbon和Eureka,从而使Feign的使用更加方便。

在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口方法上添加一些注解,代码就完成了。

二、为服务消费者整合Feign

1)项目的pom.xml增加Feign的依赖。


            org.springframework.cloud
            spring-cloud-starter-openfeign
        

2)修改启动类,为其添加@EnableFeignClients注解。

@SpringBootApplication
@EnableFeignClients
public class MicroserviceConsumerFeignApplication {

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

}

3)创建一个Feign接口,并添加@FeignClient注解。

注意,方法参数必须用@RequestParam标记,否则被认为是RequestBody而抛个数太多的异常。

@FeignClient("provider-pay") // 或者使用url属性指定请求的URL
public interface PayFeignClient {

	@GetMapping("/pay_with_params")
	public String payWithParams(@RequestParam String orderCode, @RequestParam int totalPrice);
}

@FeignClient注解中的provider-pay是一个任意的客户端名称,用于创建Ribbon负载均衡器(这里使用了Eureka,会被解析成Eureka Server服务注册表中的服务)。还可使用url属性指定请求的URL(URL可以是完整的URL或者主机名)。

4)修改Controller代码,让其调用Feign接口。

        @GetMapping("/order/feign_pay")
	public String feignPay() {
		System.out.println("订单服务开始调用支付服务...");
		String orderCode = UUID.randomUUID().toString();
		int totalPrice = 300;
		return payFeignClient.payWithParams(orderCode, totalPrice);
	}

其中,payFeignClient使用@Autowired自动注入即可。

三、自定义Feign配置

在Spring Cloud中,Feign默认使用的契约是SpringMvcContract,因此它可以使用Spring MVC的注解。我们试一下自定义Feign的配置,让它使用Feign自带的注解进行工作。

1)创建Feign的配置类。

/**
 * 该类为Feign的配置类
 * 注意:不应该在主应用程序上下文的@ComponentScan中
 * @author z_hh
 * @time 2019年2月17日
 */
@Configuration
public class FeignConfiguration {

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

2)在启动类的@ComponentScan将配置类排除,避免该类的配置信息被所有的@FeignClient共享。

@SpringBootApplication
// 排除FeignConfiguration类
@ComponentScan(excludeFilters = @ComponentScan.Filter(
		type = FilterType.ASSIGNABLE_TYPE, classes = {FeignConfiguration.class}))
@EnableFeignClients
public class MicroserviceConsumerFeignApplication {

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

}

3)Feign接口修改如下。使用@FeignClient的configuration属性指定配置类,同时将接口方法上的Spring MVC注解修改为Feign自带的注解。

/**
 * 使用@FeignClient的configuration属性,指定feign的配置类
 * @author z_hh
 * @time 2019年2月17日
 */
@FeignClient(name="provider-pay", configuration=FeignConfiguration.class) // 或者使用url属性指定请求的URL
public interface PayFeignClient2 {

	/**
	 * 使用feign自带的注解@RequestLine
	 * @param orderCode
	 * @param totalPrice
	 * @return
	 */
	@RequestLine("GET /pay_with_params")
	public String payWithParams(@Param("orderCode") String orderCode, @Param("totalPrice") int totalPrice);
}

但是,在启动的时候报了一个错:Method payWithParams not annotated with HTTP method type (ex. GET, POST),不知道什么原因,大家看下是什么问题,知道的话恳请在评论区留下解决办法!

四、Feign对继承的支持

有没有发现,Feign接口的方法签名跟服务提供者的API方法的签名一样

Feign支持继承。所以,可以将公共部分抽取到一个父接口中,从而简化Feign的开发。

比如,将POJO和API抽取到一个公共的项目里,然后服务提供者和服务消费者同时依赖这个公共项目。不过,通常情况下,不建议在服务器端与客户端共享接口,除了紧耦合之外,Feign本身并不使用Spring MVC的工作机制(方法参数映射不被继承)。关于这个,大家仁者见仁,智者见智吧。

你可能感兴趣的:(Spring,Cloud,2.x)