在Spring Cloud集群中,各个角色的通信基于REST服务,在调用服务时,需要使用REST客户端,常用,除了使用Spring自带的RestTemplate,也可使用另一个REST客户端:Feign。
使用Feign时,可以使用自带注解或第三方注解来修饰接口,使得接口具有访问Web Service的能力。
Feign还支持插件式的编码器和解码器,对请求和响应进行不同的封装和解析。
Spring Cloud将Feign集成到Netflix项目中,与Eureka、Ribbon集成时,Feign就具有负载均衡的功能。
Feign在Spring Boot Web项目的使用例子可参考:《Spring Boot 2 发布与调用REST服务》
下面例子为在Spring Cloud的使用。
开发工具:IntelliJ IDEA 2019.2.3
一、服务器端
1、创建项目
IDEA中创建一个新的SpringBoot项目,名称为“spring-feign-server”,SpringBoot版本选择2.1.10,在选择Dependencies(依赖)的界面勾选Spring Cloud Discovery ->
Eureka Server,创建完成后的pom.xml配置文件自动添加SpringCloud最新稳定版本依赖,当前为Greenwich.SR3。
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-feign-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-feign-server</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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>${spring-cloud.version}</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>
2、修改配置application.yml
修改端口号为8761;取消将自己信息注册到Eureka服务器,不从Eureka服务器抓取注册信息。
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
3、修改启动类代码SpringFeignServerApplication.java
增加注解@EnableEurekaServer
package com.example.springfeignserver; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication
@EnableEurekaServer
public class SpringFeignServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFeignServerApplication.class, args);
}
}
二、服务提供者
1、创建项目
IDEA中创建一个新的SpringBoot项目,除了名称为“spring-feign-provider”,其它步骤和上面创建服务器端一样。
2、修改配置application.yml
spring:
application:
name: spring-feign-provider
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
3、添加一个实体类User.java
package com.example.springfeignprovider; public class User {
String name;
Integer 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;
}
}
4、修改启动类代码SpringFeignProviderApplication.java
增加注解@EnableEurekaClient和@RestController;
让类在启动时读取控制台输入,决定使用哪个端口启动服务器;
增加2个测试用的控制器方法。
package com.example.springfeignprovider; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest;
import java.util.Scanner; @SpringBootApplication
@EnableEurekaClient
@RestController
public class SpringFeignProviderApplication { public static void main(String[] args) {
//SpringApplication.run(SpringFeignProviderApplication.class, args);
Scanner scan = new Scanner(System.in);
String port = scan.nextLine();
new SpringApplicationBuilder(SpringFeignProviderApplication.class).properties("server.port=" + port).run(args);
} @RequestMapping("/hello")
public String hello(HttpServletRequest request) {
return "hello world." + request.getServerPort();
} @RequestMapping(value="/user/{name}", produces = MediaType.APPLICATION_JSON_VALUE)
public User user(@PathVariable String name) {
User u = new User();
u.setName(name);
u.setAge(30);
return u;
}
}
三、服务调用者
1、创建项目
IDEA中创建一个新的SpringBoot项目,名称为“spring-feign-invoker”,SpringBoot版本选择2.1.10,在选择Dependencies(依赖)的界面勾选Spring Cloud Discovery -> Eureka Server,Spring Cloud Routing -> OpenFeign。
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-feign-invoker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-feign-invoker</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</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>${spring-cloud.version}</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>
2、修改配置application.yml
server:
port: 9000
spring:
application:
name: spring-feign-invoker
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
3、添加一个实体类User.java
package com.example.springfeigninvoker; public class User {
String name;
Integer 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;
}
}
4、添加一个客户端接口UserClient.java
package com.example.springfeigninvoker; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; //声明调用的服务名称
@FeignClient("spring-feign-provider")
public interface UserClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
String hello(); @RequestMapping(method = RequestMethod.GET, value = "/user/{name}")
User getUser(@PathVariable("name") String name);
}
5、修改启动类代码CloudInvokerApplication.java
增加注解@EnableEurekaClient和@EnableFeignClients。
package com.example.springfeigninvoker; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class SpringFeignInvokerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFeignInvokerApplication.class, args);
}
}
6、添加控制器 InvokerController.java
package com.example.springfeigninvoker; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; @RestController
@Configuration
public class InvokerController {
@Autowired
private UserClient userClient; @RequestMapping(value = "/invokeHello", method = RequestMethod.GET)
public String invokeHello(){
return userClient.hello();
} @RequestMapping(value = "/invokeUser", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String invokeUser(){
return userClient.getUser("小明").getAge().toString();
}
}
四、测试
1、启动服务器端。
浏览器访问http://localhost:8761/,正常
2、启动两个服务提供者,在控制台中分别输入8080和8081启动。
(1)浏览器访问 http://localhost:8080/user/小明
输出:{"name":"小明","age":30}
(2)浏览器访问 http://localhost:8081/user/小强
输出:{"name":"小强","age":30}
3、启动服务调用者。
(1)浏览器访问http://localhost:9000/invokeHello,页面显示在下面8080和8081端口之间切换:
hello world.8080
hello world.8081
(2)浏览器访问http://localhost:9000/invokeUser,输出:
30