springcloud(第八篇)springcloud feign

来源:互联网 发布:课时优化八上英语答案 编辑:程序博客网 时间:2024/05/16 11:54

# 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

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);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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@RestControllerpublic 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;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

注解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")@EnableFeignClientspublic 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();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

使用@FeignClient("simple")指定要访问的service id 由于hello()对应的mapping为@RequestMapping(value = "/", method = GET) 那么该方法实际调用url为 
http://simple/,因此在执行

@RequestMapping("/")    public String hello() {        return client.hello();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

调用的为SimpleApplication.java

@RequestMapping("/")    public String hello() {        return "Hello";    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

ok ~ it’s work ! more about is here 

原创粉丝点击