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. 另外一种获取redis cluster主从关系和slot分布的方法

    条条大路通罗马,通过最近学习redis cluster 观察其输出,发现了另外一种获取master-slave关系的方法. [redis@lxd-vm1 ~]$ cat get_master_slav ...

  2. python中的strip()方法

    python中字符串str的strip()方法 str.strip()就是把字符串(str)的头和尾的空格,以及位于头尾的\n \t之类给删掉. 例1: str=" python " ...

  3. ASP.NET MVC 简介(附VS2019和VSCode版示例)

    MVC可以理解为一种思想,应用在web应用程序的架构上. ASP.NET MVC的核心类是实现了IHttpHandler接口的MVCHandler,它的底层仍然是HttpHandler.HttpReq ...

  4. js和jq跳转到另一个页面或者在另一个窗口打开页面

    $("#pic").click(function(){ location.href='newpage.html'; }); 上面的相当于<a href="newpa ...

  5. SpringBoot--自动配置原理-4个注解

    一.自动配置原理 四个元注解:修饰注解的注解 @Target(ElementType.TYPE) 这个注解用在那个位置上,可以使用在类上,方法上,成员变量上 @Retention(RetentionP ...

  6. SQL Server查询中特殊字符的处理方法 (SQL Server特殊符号的转义处理)

    SQL Server查询中特殊字符的处理方法 (SQL Server特殊符号的转义处理) SQL Server查询中,经常会遇到一些特殊字符,比如单引号'等,这些字符的处理方法,是SQL Server ...

  7. Spring学习(六)

    AOP和OOP 1.OOP:Object-Oriented Programming,面向对象程序设计,是静态的,一旦类写死了就不能改变了,要更改就得修改代码重新编译,父类类型引用指向对象来实现动态性. ...

  8. AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解

    AST抽象语法树——最基础的javascript重点知识,99%的人根本不了解 javascriptvue-clicommonjswebpackast  阅读约 27 分钟 抽象语法树(AST),是一 ...

  9. Learn from Niu 2020.1.21

    1. 你一定要看计算机领域的文章. 如果你是看一堆应用,你最终还是会不知道怎么做. 从计算机到energy是降维打击, 当你学习了计算机的hot skill,再去做应用很容易. 2. 搞研究的思路: ...

  10. ps怎么把一种颜色变成另一种颜色

    使用软件:PS CC版 使用Photoshop 将图片中的一种颜色变成另一种颜色的两种方法: 1.打开图片,Ctrl+J复制一份: 2.执行菜单-选择-色彩范围,使用吸管和吸管+选取图片颜色部分,点确 ...