spring cloud feign
introduction
netflix feign
是一个类似retrofit
进行http调用框架,Feign makes writing java http clients easier
使得编写http client
代码更加简单
netflix feign
直接给出一段简单的案例
package com.lkl.netflix.feign;
import feign.*;
import feign.codec.ErrorDecoder;
import feign.codec.Decoder;
import feign.gson.GsonDecoder;
import java.io.IOException;
import java.util.List;
/**
* Created by liaokailin on 16/5/9.
*/
public class GitHubExample {
interface GitHub { // 1
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
public static void main(String... args) {
Decoder decoder = new GsonDecoder(); // 2
GitHub github = Feign.builder()
.decoder(decoder) // 3
.errorDecoder(new GitHubErrorDecoder(decoder)) // 4
.logger(new Logger.ErrorLogger()) // 5
.logLevel(Logger.Level.BASIC) // 5
.target(GitHub.class, "https://api.github.com"); // 6
System.out.println("Let's fetch and print a list of the contributors to this library.");
List<Contributor> contributors = github.contributors("netflix", "feign"); // 7
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
System.out.println("Now, let's cause an error.");
try {
github.contributors("netflix", "some-unknown-project"); // 8
} catch (GitHubClientError e) {
System.out.println(e.getMessage());
}
}
static class Contributor {
String login;
int contributions;
}
static class GitHubClientError extends RuntimeException { // 4
private String message; // parsed from json
@Override
public String getMessage() {
return message;
}
}
static class GitHubErrorDecoder implements ErrorDecoder { // 4
final Decoder decoder;
final ErrorDecoder defaultDecoder = new ErrorDecoder.Default();
GitHubErrorDecoder(Decoder decoder) {
this.decoder = decoder;
}
@Override
public Exception decode(String methodKey, Response response) {
try {
return (Exception) decoder.decode(response, GitHubClientError.class);
} catch (IOException fallbackToDefault) {
return defaultDecoder.decode(methodKey, response);
}
}
}
}
1.首先定义接口GitHub
,使用注解RequestLine
表明contributors()
方法为一个get
请求,请求相对为/repos/{owner}/{repo}/contributors
2.Decoder decoder = new GsonDecoder();
创建一个GsonDecoder
解码器,表明通过Gson
解析返回数据 3.decoder()
方法设置解码器 4.errorDecoder()
指定发生异常时的解码器,需要实现ErrorDecoder
接口,覆写decode
方法,通过指定的Decoder
解析错误信息,这里还是使用GsonDecoder
5.logger 相关的表示配置日志系你系 6.target()
方法指定访问url以及返回的类型 7.通过创建的github
对象调用contributors
获取结果 8.模拟异常情况
note: feign
使用起来很简单,其原理和retrofit
及其类似,通过接口定义访问访问,用jdk的动态代理创建接口的实现类,在类中解析方法上的注解信息用以识别用户配置的http请求信息,然后执行请求; feign可以通过ReflectiveFeign
下的newInstance()
方法看到
return (T) Proxy
.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
spring cloud feign
spring cloud feign
通过注解的封装使用起来更加简单
package com.lkl.springcloud.feign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Created by liaokailin on 16/5/11.
*/
@Configuration
@EnableAutoConfiguration
@EnableFeignClients
@RestController
public class Application {
@Autowired
GitHub gitHub;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@FeignClient(url = "https://api.github.com")
interface GitHub {
@RequestMapping(value = "/repos/{owner}/{repo}/contributors", method = RequestMethod.GET)
ResponseEntity<List<Contributor>> contributors(@PathVariable("owner") String owner, @PathVariable("repo") String repo);
}
@RequestMapping("/")
public void test(){
ResponseEntity< List<Contributor>> responseEntity = gitHub.contributors("netflix", "feign");
List<Contributor> contributors = responseEntity.getBody();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
static class Contributor {
String login;
int contributions;
}
}
注解EnableFeignClients
表明需要扫描使用FeignClient
注解的接口,在代码中定义了@FeignClient(url = "https://api.github.com")
表明该接口为一个feign接口 通过url
指定访问路径RequestMapping
表明相对路径
在代码中注入beanGitHub
,直接调用其中申明的方法即可。
重点说明下FeignClient
注解
该注解表示申明创建一个rest client bean,可以直接通过Autowired
注入使用,如果ribbon在工程中启用,则会使用load balance
进行后端请求调用,可以为FeignClient
指定value表明需要访问的serviceId
feign + ribbon + eureka
在springcloud(第七篇)springcloud ribbon with eureka中讲解了ribbon+eureka,其中使用RestTemplate
进行调用,也可以通过 feign
调用
package com.lkl.springcloud.feign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
/**
* Created by liaokailin on 16/5/9.
*/
@SpringBootApplication
@EnableDiscoveryClient
@RestController
@RibbonClient("hello")
@EnableFeignClients
public class Application {
@Autowired
HelloClient client;
@RequestMapping("/")
public String hello() {
return client.hello();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@FeignClient("simple")
interface HelloClient {
@RequestMapping(value = "/", method = GET)
String hello();
}
}
使用@FeignClient("simple")
指定要访问的service id
由于hello()
对应的mapping为@RequestMapping(value = "/", method = GET)
那么该方法实际调用url为 http://simple/
,因此在执行
@RequestMapping("/")
public String hello() {
return client.hello();
}
调用的为SimpleApplication.java
中
@RequestMapping("/")
public String hello() {
return "Hello";
}