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 使用方法和执行流程的更多相关文章

  1. 从源码角度看finish()方法的执行流程

    1. finish()方法概览 首先我们来看一下finish方法的无参版本的定义: /** * Call this when your activity is done and should be c ...

  2. 事件之onTouch方法的执行过程 及和 onClick执行发生冲突的解决办法

    转载:http://blog.csdn.net/jiangwei0910410003/article/details/17504315#quote 博主推荐: 风萧兮兮易水寒,“天真”一去兮不复还.如 ...

  3. asyncio源码分析之基本执行流程

    基于async关键字的原生协程 # 定义一个简单的原生协程cor async def cor(): print('enter cor') print('exit cor') print(type(co ...

  4. Android中onTouch方法的执行过程以及和onClick执行发生冲突的解决办法

    $*********************************************************************************************$ 博主推荐 ...

  5. JUC多线程之ThreadPoolExecutor类任务执行流程

    ThreadPoolExecutor类: ThreadPoolExecutor是我们最常用的一个线程池类,它实现了AbstractExecutorService接口.首先来看一下它的构造器及相关关键变 ...

  6. 从HashMap的执行流程开始 揭开HashMap底层实现

    心得:如何学习源码: 从某个执行过程入手,建议先从整体入手,了解底层的数据结构是怎么一步一步优化的.最后,在了解完底层的数据结构优化过程后,从重要的核心方法入手,从它的执行流程入手,先去网上搜索了解它 ...

  7. Dalvik虚拟机java方法执行流程和Method结构体分析

    Method结构体是啥? 在Dalvik虚拟机内部,每个Java方法都有一个对应的Method结构体,虚拟机根据此结构体获取方法的所有信息. Method结构体是怎样定义的? 此结构体在不同的andr ...

  8. django—Form组件校验方法(is_valid)执行流程

    1.从is_valid方法入手 def is_valid(self): """Return True if the form has no errors, or Fals ...

  9. 第二天 ci执行流程

    第二天 ci执行流程 welcome 页面 this this->load 单入口框架index.php 两个文件夹 system application定义 定义常亮路径 载入 codeign ...

随机推荐

  1. 视频中“5s后可跳过广告” 设计目的

    来源:https://wen.woshipm.com/question/detail/0quoes.html 1.保证你在看.用户关掉广告这5秒内,他的眼睛会盯着屏幕,因为他知道5秒之后就能跳过广告. ...

  2. Codeforce 584A - Olesya and Rodion

    Olesya loves numbers consisting of n digits, and Rodion only likes numbers that are divisible by t. ...

  3. Virtual DOM(八)

    Virtual DOM 这个概念相信大部分人都不会陌生,它产生的前提是浏览器中的 DOM 是很“昂贵"的,为了更直观的感受,我们可以简单的把一个简单的 div 元素的属性都打印出来,如图所示 ...

  4. AntDesign(React)学习-6 Menu展示数据

    1.官方文档请查看https://ant.design/components/menu-cn/antPro自带的菜单功能很强大,但是太复杂了,感觉大部分功能都用不上,下面实现一个简单从后台动态获取菜单 ...

  5. Pycharm常用快捷捷捷啊键= =

    超多快捷键的其实,懒得都记住(主要是记不住……) 这里记录一下自己觉得用了确实会很省事的,特别是当你没有鼠标的时候 = = 超常用的 Ctrl + /  注释该行 Ctrl + D  复制该行到下一行 ...

  6. DE1_MSEL

    基础的一般实验:01001(现在用的)或10010 马上换linux,做个记录: sd卡启动linux系统时,启动开关0至4位拨至00000

  7. configparser模块简介

    https://www.cnblogs.com/plf-Jack/p/11170284.html

  8. go语言 实现哈希算法

    验证结果网址 http://www.fileformat.info/tool/hash.htm "golang.org/x/crypto/md4"不存在时,解决方法: cd $GO ...

  9. 转载:TDM协议

    转自http://www.wangdali.net/i2s/ 1. PCM简介 PCM (Pulse Code Modulation) 是通过等时间隔(即采样率时钟周期)采样将模拟信号数字化的方法.图 ...

  10. Tomcat/conf/server.xml文件中docBase和path的说明

    Tomcat的项目部署方式有以下三种: 1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法.2.在tomcat安装目录中有一个conf文件夹,打 ...