创建公共接口 首先我们来创建一个普通的maven工程,叫做hello-service-api,由于我们要在这一个项目中使用SpringMVC的注解,因此创建成功之后,需要添加spring-boot-starter-web依赖,如下:
1 2 3 4 5 6 7 8 9 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.sang</groupId> <artifactId>commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
commons是我的另外一个maven项目,里边提供了Book这个类,因为我的hello-service-api一会要用到Book类,当然这里你也可以直接在hello-service-api中定义一个Book类。
项目创建好之后,我们在这个项目中提供一个HelloSerivce接口,如下:
1 2 3 4 5 6 7 8 9 10 11 @RequestMapping("/hs2") public interface HelloService { @RequestMapping(value = "/hello1", method = RequestMethod.GET) String hello(@RequestParam("name") String name); @RequestMapping(value = "/hello2", method = RequestMethod.GET) Book hello(@RequestHeader("name") String name, @RequestHeader("author") String author, @RequestHeader("price") Integer price) throws UnsupportedEncodingException; @RequestMapping(value = "/hello3", method = RequestMethod.POST) String hello(@RequestBody Book book); }
这次我做了请求窄化,给请求定义了前缀/hs2。
服务提供者中实现接口 hello-service-api工程写好之后,我们在服务提供者中添加对hello-service-api工程的依赖,如下:
1 2 3 4 5 <dependency> <groupId>org.sang</groupId> <artifactId>hello-service-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
然后在服务提供者中创建BookController2实现HelloService接口,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @RestController public class BookController2 implements HelloService { @Override public String hello(@RequestParam("name") String name) { return "hello " + name + "!"; } @Override public Book hello(@RequestHeader("name") String name, @RequestHeader("author") String author, @RequestHeader("price") Integer price) throws UnsupportedEncodingException { org.sang.Book book = new org.sang.Book(); book.setName(URLDecoder.decode(name,"UTF-8")); book.setAuthor(URLDecoder.decode(author,"UTF-8")); book.setPrice(price); System.out.println(book); return book; } @Override public String hello(@RequestBody Book book) { return "书名为:" + book.getName() + ";作者为:" + book.getAuthor(); } }
实现了HelloService接口当然就要实现HelloService接口中的方法,这里不需要在方法上面添加@RequestMapping注解,这些注解在父接口中都有,不过在Controller上还是要添加@RestController注解,另外需要注意的是,方法中的参数@RequestHeader和@RequestBody注解还是要添加,@RequestParam注解可以不添加。
服务消费者中继承接口 写完了服务提供者之后,接下来我们再来看看服务消费者。首先在服务消费者中添加对hello-service-api的依赖,然后新建一个HelloService2类继承hello-service-api中的HelloService接口,如下:
1 2 3 @FeignClient("hello-service") public interface HelloService2 extends HelloService { }
这个接口中不需要添加任何方法,方法都在父接口中,这里只需要在类上面添加@FeignClient(“hello-service”)注解来绑定服务即可。
然后在Controller中提供相应的测试接口,如下:
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 @RestController public class FeignConsumerController { @Autowired HelloService2 helloService2; @RequestMapping("/hello1") public String hello1() { return helloService2.hello("张三"); } @RequestMapping(value = "/hello2") public Book hello2() throws UnsupportedEncodingException { Book book = helloService2.hello(URLEncoder.encode("三国演义","UTF-8"), URLEncoder.encode("罗贯中","UTF-8"), 33); System.out.println(book); return book; } @RequestMapping("/hello3") public String hello3() { Book book = new Book(); book.setName("红楼梦"); book.setPrice(44); book.setAuthor("曹雪芹"); return helloService2.hello(book); } }
测试 最后,我们依次启动eureka-server、provider和feign-consumer,然后访问相应的接口,测试结果如下:
http://localhost:2005/hello1:
http://localhost:2005/hello2:
http://localhost:2005/hello3:
总结 通过上面的介绍,应该已经体会到了Feign继承特性的方便之处了,这种方式用起来确实很方面,但是也带来一个问题,就是服务提供者和服务消费者的耦合度太高,此时如果服务提供者修改了一个接口的定义,服务消费者可能也得跟着变化,进而带来很多未知的工作量,因此在使用继承特性的时候,要慎重考虑。