<!-- feign client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.1.1.RELEASE</version> </dependency>
@Validated @FeignClient(name="nuts", url = "${nuts.sms.smsNoticeUrl}",configuration = {HttpClientProxyConfiguration.class}) public interface NoticeSao { @PostMapping("/tesyt") @Async ResponseDTO sendSms(@Valid NoticeDTO noticeDTO, URI uri); }
@FeignClient(name="nuts",2 url = "${nuts.sms.smsNoticeUrl}",configuration = {HttpClientProxyConfiguration.class}) public interface NoticeSao { @PostMapping("/tesyt") @Async ResponseDTO sendSms(NoticeDTO noticeDTO,1 URI uri); } public void apply(RequestTemplate template) { // 3 template.target("http://test/test"); }
@Component @Slf4j public class NutsOpenApiInterceptor implements RequestInterceptor {
@FeignClient(name="nuts",3.url = "",configuration = {HttpClientProxyConfiguration.class}) public interface NoticeSao {
FeignClientsRegistrar 的做用:spring
1.註冊默認的configuration,app
2.註冊FeignClients即有@FeignClient註解的接口異步
3.註冊@FeignClient(name="nuts",3.url = "",configuration = {HttpClientProxyConfiguration.class})裏的configuration到當前的contentasync
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
@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;ide
1.建立一個 FeignClientFactoryBean 在初始話時,注入各類須要的對象。優化
2.須要注入接口的地方,會調用 FeignClientFactoryBean.getBean方法ui
3.getBean中初始話builder Feign.Builderthis
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.使用動態代理生成代理類 ReflectiveFeignurl
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. 調用請求具體的方法 SynchronousMethodHandlerspa
@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不支持這樣寫。
@PostMapping("/")
@Async
Future<ResponseDTO> sendSms(NoticeDTO noticeDTO);
@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); }