FeignClient和RestFul使用笔记
简介
这篇文章主要讲解FeignClient解析和RestFul的开发使用和一些简单注意事项。
- FeignClient分两种介绍,一个指定请求、一个注册中心寻找;也就是如何动态url和指定url、注册中心寻找
- RestFul的几种解读和差异:GetMapping、PostMapping、PutMapping、DeleteMapping、PatchMapping
实践讲解
FeignClient例子
在feiignClient之前,我们来编写如下代码
UserCenterClient 客户端调用类
package com.lgh.client;
import lombok.Data;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import java.net.URI;
@FeignClient(name = "test", url = "EMPTY")
public interface UserCenterClient {
@PostMapping("/feign/{id}/client")
public String client(URI uri, @RequestHeader(value = "token", required = true) String token,
@PathVariable("id") int id,
@RequestBody User user);
@Data
class User {
private String userId;
private String passwd;
}
}
调用方式 TestController
package com.lgh.controller;
import com.lgh.client.UserCenterClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.net.URISyntaxException;
@Api(tags = "测试feignClient")
@RestController
@RequestMapping("/feign")
@Slf4j
public class TestController {
@Autowired
private UserCenterClient userCenterClient;
@ApiOperation("测试springmvc和feignClient")
@PostMapping("/{id}/client")
public String client(@RequestHeader(value = "token", required = true) String token,
@PathVariable("id") int id,
@RequestBody UserCenterClient.User user) throws URISyntaxException {
return userCenterClient
.client(new URI("http://localhost:8080")
, token, id, user);
}
}
上面地址是动态指定url来调用http://localhost:8080
服务类TestController
package com.lgh.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Api(tags = "测试feignClient")
@RestController
@RequestMapping("/feign")
@Slf4j
public class TestController {
@ApiOperation("测试springmvc和feignClient")
@PostMapping("/{id}/client")
public String client(@RequestHeader(value = "token", required = true) String token,
@PathVariable("id") int id, @RequestBody User user) {
log.info("token={},id={},user={}", token, id, user.toString());
return "OK";
}
@Data
class User {
private String userId;
private String passwd;
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", passwd='" + passwd + '\'' +
'}';
}
}
}
通过如上例子可以动态指定url调用服务器的地址,只要参数中存在URI即可。具体实现都在代理类中解析,分四步
- feign.ReflectiveFeign#newInstance解析FeignClient
- feign.Contract.BaseContract#parseAndValidateMetadata解析元数据
- feign.Contract.BaseContract#parseAndValidateMetadata(java.lang.Class<?>, java.lang.reflect.Method) 解析对参数判断,设置urlIndex的值寻找target目标,如下代码
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
// ……
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
}
}else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {
//……
}
//……
- feign.ReflectiveFeign.BuildTemplateByResolvingArgs#create构造中判断是否有指定url
public RequestTemplate create(Object[] argv) {
//……
if (metadata.urlIndex() != null) {
int urlIndex = metadata.urlIndex();
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
mutable.target(String.valueOf(argv[urlIndex]));
}
//……
}
FeignClient解析
FeignClient注解我们比较关注的是几个属性;
- value或者name
这里是设置请求的应用,当url和参数的URI未设置时,这里生效即服务注册名称,FeignClient调用时从注册中心寻找轮询。 - url
指定url。当参数为存在uri时,此参数生效,即FeignClient请求的目标服务地址 - path 这里是请求路径,当方法参数未存在URI时,此路径生效
RestFul用法
其实RestFul每种都有自己特点,主要做的就是规约。也是spring官网对DispatcherServlet的完善补充。具体其实有get和post方法请求即可,但是为了更好归约和编程规范,便出现RestFul概念。
/**
* @author Juergen Hoeller
* @author Arjen Poutsma
* @author Sam Brannen
* @since 2.5
* @see GetMapping
* @see PostMapping
* @see PutMapping
* @see DeleteMapping
* @see PatchMapping
*/
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
//…………
}
- GetMapping
从服务器获取参数时,使用get请求类型,这里获取参数不能通过RequestBody设置,因为参数在request的Param中。也就是会限制路径长度,使用时要预估参数是否超限。 - PostMapping
上送提交参数,是一次性上送全部参数时使用,和PatchMapping相对应,因为PatchMapping也就是部分提交不具备幂等性,PostMapping全量表单提交,具备幂等性,这里是以post请求方式提交,是流时传输,一般来说不限制大小。 - PutMapping
更新数据,也就是需要更新记录时使用此方法 - DeleteMapping
删除数据,删除服务器数据时使用此方式 - PatchMapping
部分更新数据,不具备幂等性是PostMapping的扩展
总结
1)FeignClient中如果要动态请求URL,则可以在方法入参中传入URI
2)FeignClient如果要设置指定的URL可以设置FeignClient属性URL
3)RestFul使用特性每种方法均有意义。get请求无法通过@RequestBody获取参数值,可通过@RequestParam指定参数值
4)PATCH和PUT方法的区别,两种均是更新操作。PUT全量,PATCH部分。PUT具备幂等意义,PATCH不具备。
参考文献
[1] PATCH和PUT方法的区别