openfeign 使用方法和执行流程
1.用法
1.1引入依赖
<!-- feign client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
1.3参数校验(利用MethodValidationInterceptor 再springContext中利用@Validated生成代理对象来进行参数校验)
@Validated
@FeignClient(name="nuts", url = "${nuts.sms.smsNoticeUrl}",configuration = {HttpClientProxyConfiguration.class})
public interface NoticeSao { @PostMapping("/tesyt")
@Async
ResponseDTO sendSms(@Valid NoticeDTO noticeDTO, URI uri);
}
1.2 url配置的优化级 从高到低依次覆盖
@FeignClient(name="nuts", url = "${nuts.sms.smsNoticeUrl}",configuration = {HttpClientProxyConfiguration.class})
public interface NoticeSao { @PostMapping("/tesyt")
@Async
ResponseDTO sendSms(NoticeDTO noticeDTO, URI uri);
} public void apply(RequestTemplate template) {
// template.target("http://test/test");
}
1.2.1 在参数中加上URI
1.3.2 @FeignClient 中的url带有http参数
1.4.3 在拦截器中使用 template.target("http://test/test");
1.3配置拦截器 (注意拦截器使用范围)
@Component
@Slf4j
public class NutsOpenApiInterceptor implements RequestInterceptor {
1.4配置 HttpClientProxyConfiguration
@FeignClient(name="nuts",3.url = "",configuration = {HttpClientProxyConfiguration.class})
public interface NoticeSao {
1.5遗留问题
1.5.1 再集群中服务发现 和url 手动指定的矛盾化解
2.原理
2.1 启用配置类
2.1.1 FeignAutoConfiguration
2.1.2 @EnableFeignClients (FeignClientsRegistrar)
FeignClientsRegistrar 的作用:
1.注册默认的configuration,
2.注册FeignClients即有@FeignClient注解的接口
3.注册@FeignClient(name="nuts",3.url = "",configuration = {HttpClientProxyConfiguration.class})里的configuration到当前的content
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
2.2 初始FeignContext
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
public class FeignContext extends NamedContextFactory<FeignClientSpecification> { public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
} }
为@FeignClient注解的类创建springContext,parentContext均为当前的springContxt;
2.2 创建@FeignClient注解的接口的bean对象
1.创建一个 FeignClientFactoryBean 在初始话时,注入各种需要的对象。
2.需要注入接口的地方,会调用 FeignClientFactoryBean.getBean方法
3.getBean中初始话builder Feign.Builder
protected void configureUsingConfiguration(FeignContext context,
Feign.Builder builder) {
Logger.Level level = getOptional(context, Logger.Level.class);
if (level != null) {
builder.logLevel(level);
}
Retryer retryer = getOptional(context, Retryer.class);
if (retryer != null) {
builder.retryer(retryer);
}
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
if (errorDecoder != null) {
builder.errorDecoder(errorDecoder);
}
Request.Options options = getOptional(context, Request.Options.class);
if (options != null) {
builder.options(options);
}
Map<String, RequestInterceptor> requestInterceptors = context
.getInstances(this.contextId, RequestInterceptor.class);
if (requestInterceptors != null) {
builder.requestInterceptors(requestInterceptors.values());
} if (this.decode404) {
builder.decode404();
}
}
4.使用动态代理生成代理类 ReflectiveFeign
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>(); for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler); for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
5. 调用请求具体的方法 SynchronousMethodHandler
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while (true) {
try {
return executeAndDecode(template);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
问题:
目前feign不支持 异步调用接收返回值
下面写法是错误的,目前feign不支持这样写。
@PostMapping("/")
@Async
Future<ResponseDTO> sendSms(NoticeDTO noticeDTO);
采用另一种解决方案,在service中做异步
@Async
public Future<ResponseDTO> asyncSendSms(NoticeDTO noticeDTO){
ResponseDTO responseDTO = noticeSao.sendSms(noticeDTO);
return new AsyncResult(responseDTO);
}
用法:
public class BspEncoder implements Encoder { private static final String CONTENT_TYPE_HEADER; private static final Pattern CHARSET_PATTERN; static {
CONTENT_TYPE_HEADER = "Content-Type";
CHARSET_PATTERN = Pattern.compile("(?<=charset=)([\\w\\-]+)");
} @Value("${accessCode}")
private String accessCode; @Value("${checkword}")
private String checkword; private ContentProcessor processor=new UrlencodedFormContentProcessor(); @Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
//1.将object生成xml String
com.sf.wms.sao.encoder.annotation.Request annotation = AnnotationUtils.findAnnotation((Class<?>) bodyType, com.sf.wms.sao.encoder.annotation.Request.class);
Request request=new Request();
request.setService(annotation.service());
request.setLang(annotation.lang());
request.setHead(accessCode);
String xml="";
try {
xml= JAXBUtil.writeToString(request, (Class) bodyType, request.getClass());
} catch (Exception e) {
e.printStackTrace();
}
//instanceof 判断某个对象是否是某一类型
// obj.getClass().isArray();
//2.生成 verifyCode
String verifyCode = md5AndBase64(xml + checkword); Map<String,Object> map=new HashMap<>();
map.put("xml",xml);
map.put("verifyCode",verifyCode); String contentTypeValue = getContentTypeValue(template.headers());
val charset = getCharset(contentTypeValue);
processor.process(template,charset,map);
} private String getContentTypeValue (Map<String, Collection<String>> headers) {
for (val entry : headers.entrySet()) {
if (!entry.getKey().equalsIgnoreCase(CONTENT_TYPE_HEADER)) {
continue;
}
for (val contentTypeValue : entry.getValue()) {
if (contentTypeValue == null) {
continue;
}
return contentTypeValue;
}
}
return null;
} private Charset getCharset (String contentTypeValue) {
val matcher = CHARSET_PATTERN.matcher(contentTypeValue);
return matcher.find()
? Charset.forName(matcher.group(1))
: UTF_8;
} private static byte[] md5(String data) {
return DigestUtils.md5(data);
} private static String md5AndBase64(String data) {
return base64Encode(md5(data));
} private static String base64Encode(byte[] bytes) {
return Base64.encodeBase64String(bytes);
}
}
@FeignClient(name = "bsp", url = "${logisticsOrderUrl}",configuration = {BspConfiguration.class})
public interface BspLogisticsOrderSao { @PostMapping(consumes = "application/x-www-form-urlencoded;charset=UTF-8")
BspLogisticsOrderDTO getLogisticsOrder(LogisticsOrderListModel model);
}
openfeign 使用方法和执行流程的更多相关文章
- 从源码角度看finish()方法的执行流程
1. finish()方法概览 首先我们来看一下finish方法的无参版本的定义: /** * Call this when your activity is done and should be c ...
- 事件之onTouch方法的执行过程 及和 onClick执行发生冲突的解决办法
转载:http://blog.csdn.net/jiangwei0910410003/article/details/17504315#quote 博主推荐: 风萧兮兮易水寒,“天真”一去兮不复还.如 ...
- asyncio源码分析之基本执行流程
基于async关键字的原生协程 # 定义一个简单的原生协程cor async def cor(): print('enter cor') print('exit cor') print(type(co ...
- Android中onTouch方法的执行过程以及和onClick执行发生冲突的解决办法
$*********************************************************************************************$ 博主推荐 ...
- JUC多线程之ThreadPoolExecutor类任务执行流程
ThreadPoolExecutor类: ThreadPoolExecutor是我们最常用的一个线程池类,它实现了AbstractExecutorService接口.首先来看一下它的构造器及相关关键变 ...
- 从HashMap的执行流程开始 揭开HashMap底层实现
心得:如何学习源码: 从某个执行过程入手,建议先从整体入手,了解底层的数据结构是怎么一步一步优化的.最后,在了解完底层的数据结构优化过程后,从重要的核心方法入手,从它的执行流程入手,先去网上搜索了解它 ...
- Dalvik虚拟机java方法执行流程和Method结构体分析
Method结构体是啥? 在Dalvik虚拟机内部,每个Java方法都有一个对应的Method结构体,虚拟机根据此结构体获取方法的所有信息. Method结构体是怎样定义的? 此结构体在不同的andr ...
- django—Form组件校验方法(is_valid)执行流程
1.从is_valid方法入手 def is_valid(self): """Return True if the form has no errors, or Fals ...
- 第二天 ci执行流程
第二天 ci执行流程 welcome 页面 this this->load 单入口框架index.php 两个文件夹 system application定义 定义常亮路径 载入 codeign ...
随机推荐
- 【Unity|C#】基础篇(17)——字符串处理(String/StringBuilder)
[学习资料] <C#图解教程>(第25章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...
- Max Sum Plus Plus HDU - 1024 基础dp 二维变一维的过程,有点难想
/* dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j]) (0<k<j) dp[i][j-1]+a[j]表示的是前j-1分成i组,第j个必 ...
- UTF自动化测试工具
自UFT推出后,QTP慢慢退出历史舞台 UFT测试的基本流程:录制测试脚本—-编辑测试脚本—-调试测试脚本—-运行测试脚本—-分析测试结果 UFT(QTP)介绍 http://blog.csdn. ...
- vlan划分、本征vlan配置、中继
命令部分: vlan划分(全局模式) vlan name v10 no shu no shu switchport access vlan vlan name v20 inter vlan no sh ...
- 机器学习笔记(十一)OCR技术的应用
1.介绍OCR: OCR(Photo optical character recognition 照片光学字符识别) 应用于读取电子照片中的文字. 2.算法思路: ① 识别文字区域: ② 字符切分: ...
- PP: Tripoles: A new class of relationships in time series data
Problem: ?? mining relationships in time series data; A new class of relationships in time series da ...
- C++——字符串处理
11.用字符数组存储和处理字符串 字符数组的声明和引用 字符串: 字符串常量 “china”,没有字符串变量,用字符数组来存放字符串,字符串以‘\0’结束. 字符串数组的初始化: 逐个输出输入字符串 ...
- Token:服务端身份验证的流行方案
01- 身份认证 服务端提供资源给客户端,但是某些资源是有条件的.所以服务端要能够识别请求者的身份,然后再判断所请求的资源是否可以给请求者. token是一种身份验证的机制,初始时用户提交账号数据给服 ...
- Java EE 7 API
学习Java必备资源,下载链接: https://pan.baidu.com/s/1P1xzuoGJCIuZlYBbPSbM_Q 提取码: dtui 复制这段内容后打开百度网盘手机App,操作更方便哦
- Shashlik Cooking
Long story short, shashlik is Miroslav's favorite food. Shashlik is prepared on several skewers simu ...