阅读完需:约 4 分钟
上篇我们了解了Feign的基本使用,在HelloService类中声明接口时,我们发现这里的代码可以直接从服务提供者的Controller中复制过来,这些可以复制的代码Spring Cloud Feign对它进行了进一步的抽象,这里就用到了Feign的继承特性,本文我们就来看看如何利用Feign的继承特性来进一步简化我们的代码。
创建公共接口
将 provider 和 openfeign 中公共的部分提取出来,一起使用。 (接口共用)
首先我们来创建一个普通的maven工程,叫做hello-service-api,由于我们要在这一个项目中使用SpringMVC的注解,因此创建成功之后,需要添加spring-boot-starter-web依赖,如下:
由于这个模块要被其他模块所依赖,所以这个模块是一个 Maven 项目(boot项目不好被依赖),但是由于这个模块要用到 SpringMVC 的东西,因此在创建成功后,给这个模块添加一个 web 依赖,导入 SpringMVC 需要的一套东西
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.javaboy</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
然后定义公共接口,就是provider 和 openfeign 中公共的部分:
public interface IUserService {
@GetMapping("/hello")
String hello();//这里的方法名无所谓,随意取
@GetMapping("/hello2")
String hello2(@RequestParam("name") String name);
@PostMapping("/user2")
User addUser2(@RequestBody User user);
@DeleteMapping("/user2/{id}")
void deleteUser2(@PathVariable("id") Integer id);
@GetMapping("/user3")
void getUserByName(@RequestHeader("name") String name) throws UnsupportedEncodingException;
}
定义完成后,接下来,在 provider 和 openfeign 中,分别引用该模块:
<dependency>
<groupId>org.javaboy</groupId>
<artifactId>hello-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
服务提供者中实现接口
@RestController
public class HelloController implements IUserService {
@Value("${server.port}")
Integer port;
@Override
public String hello() {
String s = "hello javaboy:" + port;
System.out.println(s);
int i = 1 / 0;
return s;
}
@Override
public String hello2(String name) {
System.out.println(new Date() + ">>>" + name);
return "hello " + name;
}
@PostMapping("/user1")
public User addUser1(User user) {
return user;
}
@Override
public User addUser2(@RequestBody User user) {
return user;
}
@PutMapping("/user1")
public void updateUser1(User user) {
System.out.println(user);
}
@PutMapping("/user2")
public void updateUser2(@RequestBody User user) {
System.out.println(user);
}
@DeleteMapping("/user1")
public void deleteUser1(Integer id) {
System.out.println(id);
}
@Override
public void deleteUser2(@PathVariable Integer id) {
System.out.println(id);
}
@Override
public void getUserByName(@RequestHeader String name) throws UnsupportedEncodingException {
System.out.println(URLDecoder.decode(name, "UTF-8"));
}
}
实现了HelloService接口当然就要实现HelloService接口中的方法,方法的实现还是和以前一样。不同的是我这里不需要在方法上面添加@RequestMapping注解,这些注解在父接口中都有,不过在Controller上还是要添加@RestController注解,另外需要注意的是,方法中的参数@RequestHeader和@RequestBody注解还是要添加,@RequestParam注解可以不添加。
服务消费者中继承接口
写完了服务提供者之后,接下来我们再来看看服务消费者。首先在服务消费者中添加对hello-service-api的依赖,然后HelloService类继承hello-service-api中的HelloService接口,如下:
@FeignClient(value = "provider")
public interface HelloService extends IUserService {
}
这个接口中不需要添加任何方法,方法都在父接口中,这里只需要在类上面添加@FeignClient(“provider”)注解来绑定服务即可。
Controller调用接口的方法和以前一样:
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello() throws UnsupportedEncodingException {
String s = helloService.hello2("uuuuu");
System.out.println(s);
User user = new User();
user.setId(1);
user.setUsername("uuuuu");
user.setPassword("123");
User u = helloService.addUser2(user);
System.out.println(u);
helloService.deleteUser2(1);
helloService.getUserByName(URLEncoder.encode("阿瑟东", "UTF-8"));
return helloService.hello();
}
}
关于继承特性:
- 使用继承特性,代码简洁明了不易出错。服务端和消费端的代码统一,一改俱改,不易出错。这是优点也是缺点,这样会提高服务端和消费端的耦合度。
- 之前所讲的参数传递,在使用了继承之后,依然不变,参数该怎么传还是怎么传。