Feign简介
Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign.
简而言之:
- Feign 采用的是基于接口的注解
- Feign 整合了ribbon
准备工作
继续用上一节的工程, 启动eureka-server,端口为8761; 启动service-hello两次,端口分别为8762 、8773.
创建service-feign项目
pom
<?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">
<artifactId>service-feign</artifactId>
<groupId>comm.bamboo</groupId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.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.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<!-- spring boot jar -->
<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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RC1</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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
yml
server:
port: 8765
spring:
application:
name: service-feign
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
java代码
FeignApplication.java
package com.bamboo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
*
* FeignApplication
*
* Application
*/
@SpringBootApplication
@EnableDiscoveryClient//向服务中心注册
@EnableFeignClients//@EnableFeignClients注解开启Feign功能
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
SchedualServiceHello.java
这个接口是整个最重要和注意的地方
- 通过@ FeignClient(“服务名”),来绑定并指定调用哪个服务
- RequestMapping中的配置要和提供服务方提供的方法名和RequestMethod一摸一样
因此从 RequestMapping可以看出它是通过http协议进行的远程调用,而dubbo则是通过自定义的协议进行的二进制调用。
package com.bamboo;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 定义一个feign接口,通过@ FeignClient(“服务名”),来绑定并指定调用哪个服务
* Created by babmoo on 2017/10/21.
*/
@FeignClient(value = "service-hello")
public interface SchedualServiceHello {
//使用的springmvc注解
@RequestMapping(value = "/hello",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
HelloController.java
package com.bamboo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by xialeme on 2017/10/21.
*/
@RestController
public class HelloController {
@Autowired
SchedualServiceHello schedualServiceHello;
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String sayHi(@RequestParam String name){
return schedualServiceHello.sayHiFromClientOne(name);
}
}
运行服务组件并调用服务
- 运行eureka-server
- 运行service-hello
- 修改service-hello的端口8763再次运行
- 运行service-feign
启动程序,多次访问http://localhost:8765/hello?name=forezp,浏览器交替显示:
hello from port:8762
hello from port:8763
显示结果和上一篇的结果一样的,说明至少在形式上他们都进行了轮询方式的负载均衡。其实他们实际都是ribbon模块进行的负载均衡
总结
其实通过Feign封装了HTTP调用服务方法,使得客户端像调用本地方法那样直接调用方法,类似Dubbo中暴露远程服务的方式。
区别在于Dubbo是基于私有二进制协议,而Feign本质上还是个HTTP客户端