Spring Cloud Feign(宣告式服務呼叫)(1)
Spring Cloud Feign它基於Netflix Feign實現,整合了Spring Cloud Ribbon與Spring Cloud Hystrix,除了提供這兩者的強大功能,它還提供了一種宣告式的Web服務客戶端定義方式。
1.下面首先建立一個Spring Boot基礎工程取名為feign-consumer並在其pom.xml檔案中加入spring-cloud-starter-eureka和spring-cloud-starter-feign依賴。
<?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.example</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>2.0.5.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> <spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</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-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>${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.在主類上新增@EnableFeignClients註解開啟Spring Cloud Feign的支援功能:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
3.定義HelloService介面,通過@FeignClient註解指定服務名來繫結服務,然後使用Spring MVC的註解來繫結具體該服務提供的REST介面。
@FeignClient("hello-service")//用於繫結名為hello-service服務
public interface HelloService {
@RequestMapping("/hello")
public String hello(String id);
}
4.最後建立一個控制器來實現對Feign客戶端的呼叫。使用@AutoWired直接注入HelloService例項,並在該控制器中直接呼叫hello-service服務發起的/hello介面的呼叫。
@RestController public class ConsumerController { @Autowired HelloService helloService; @GetMapping("/feign-consumer") public String helloConsumer(String id){ return helloService.hello(id); } }
5.修改application.properties檔案:
spring.application.name=feign-consumer
server.port=9001
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
不過此時是沒有引數繫結能力的所以沒有列印id。
引數繫結
首先擴充套件一下服務提供者(hello-service)。
@RestController
public class HelloController {
private final Logger logger=Logger.getLogger(getClass());
@RequestMapping("/hello")
public String index() throws InterruptedException {
// int sleepTime=new Random().nextInt(3000);
// logger.info("sleep:"+sleepTime);
// Thread.sleep(sleepTime);
logger.info(new Date());
return "Hello"+new Date()+"---"+new Random().nextInt();
}
@RequestMapping(value = "/hello1", method = RequestMethod.GET)
public String hello1(@RequestParam String name) {
return "hello " + name + "!";
}
@RequestMapping(value = "/hello2", method = RequestMethod.GET)
public Map<String,Object> hello2(@RequestHeader String name, @RequestHeader String author, @RequestHeader Integer price) throws UnsupportedEncodingException {
Map<String,Object> map = new HashMap<String,Object>();
map.put("name",URLDecoder.decode(name));
map.put("author",URLDecoder.decode(author));
return map;
}
@RequestMapping(value = "/hello3", method = RequestMethod.POST)
public String hello3(@RequestBody Map<String,Object> book) {
return "書名為:" + book.get("name") + ";作者為:" + book.get("author");
}
@RequestMapping(value = "/hello4", method = RequestMethod.POST)
public String hello4(@RequestBody User user) {
return "使用者名稱:" + user.getName() + ";年齡為:" + user.getAge();
}
}
User類:
public class User {
private String name;
private Integer age;
public User(){}
public User(String name, Integer age){
this.name=name;
this.age=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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
然後在feign-consumer中也建立逾期一樣的User類。
然後再HelloService介面中新增上述介面的繫結:
@FeignClient("hello-service")//用於繫結名為hello-service服務
public interface HelloService {
@RequestMapping("/hello")
public String hello();
@RequestMapping(value = "/hello1", method = RequestMethod.GET)
String hello(@RequestParam("name") String name);
@RequestMapping(value = "/hello2", method = RequestMethod.GET)
Map<String,Object> hello(@RequestHeader("name") String name, @RequestHeader("author") String author, @RequestHeader("price") Integer price);
@RequestMapping(value = "/hello3", method = RequestMethod.POST)
String hello(@RequestBody Map<String,Object> book);
@RequestMapping(value = "/hello4", method = RequestMethod.POST)
String hello(@RequestBody User user);
}
這裡需要注意在繫結引數時,@RequestParam,@RequestHeader等可以指定引數名稱的註解的value引數不能少。在Feign中繫結引數必須通過value來指定具體的引數名不然會丟擲IlleglStateException異常,value屬性不能為空。
最後控制器新增上述介面:
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@GetMapping("/feign-consumer")
public String helloConsumer(){
return helloService.hello();
}
@RequestMapping("/hello1")
public String hello1() {
return helloService.hello("張三");
}
@RequestMapping(value = "/hello2")
public Map<String,Object> hello2() throws UnsupportedEncodingException {
Map<String,Object> book = helloService.hello(URLEncoder.encode("三國演義","UTF-8"), URLEncoder.encode("羅貫中","UTF-8"), 33);
System.out.println(book);
return book;
}
@RequestMapping("/hello3")
public String hello3() {
Map<String,Object> book = new HashMap<String,Object>();
book.put("name","三國演義");
book.put("author","羅貫中");
return helloService.hello(book);
}
@RequestMapping("/hello4")
public String hello4() {
User user=new User("劉德華",99);
return helloService.hello(user);
}
}