基础操作
pom依赖
OpenFeign 是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置application.yml
#====《跨服务HTTP接口请求工具》====
feign:
client:
config:
#可指定需要配置的:服务名称
# manage-client:
#或 默认配置:全局
default:
#日志打印级别
loggerLevel: basic
#跨服务接口请求超时
readTimeout: 5000
#跨服务请求连接超时
connectTimeout: 5000
服务启动类
启动类加上注解:@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class OpenFeignServer {
public static void main(String[] args) {
SpringApplication.run(OpenFeignServer.class, args);
}
}
基础跨服务调用
@FeignClient("serverName")
public interface AdminServiceClient {
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.GET, produces = {"application/json"}, consumes = {"application/glue+json"})
<T> T doGet(@RequestParam("params") String params);
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.PUT, produces = {"application/json"}, consumes = {"application/communication+json"})
<T> T doPut(@RequestBody Object params);
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.POST, produces = {"application/json"}, consumes = {"application/communication+json"})
<T> T doPost(@RequestBody Object params);
}
动态IP+URL请求 + 动态编码器\解码器
自定义跨服务请求,Encoder编译器
import com.details.utils.ConvertUtils;
import com.details.utils.JsonUtils;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.RequestTemplate;
import feign.Util;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
@Slf4j
public class FeignEncoder implements Encoder {
ObjectMapper mapper = new ObjectMapper();
@SneakyThrows
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
log.info("Feign requset encode details: {}", object);
try {
Map<String, Collection<String>> headers = template.headers();
Collection<String> contentType = headers.get("Content-Type");
if (CollectionUtils.isNotEmpty(contentType) && contentType.contains("application/json") && !(object instanceof String)) {
template.body(JsonUtils.object2Json(object));
}
else if (object instanceof String) {
template.body(object.toString());
} else {
JavaType javaType = this.mapper.getTypeFactory().constructType(bodyType);
template.body(ConvertUtils.writeAsBytes(javaType, object), Util.UTF_8);
}
} catch (Exception e) {
throw new EncodeException(String.format("%s is not a type supported by this encoder.", object.getClass()));
}
}
}
自定义跨服务响应,Decoder 解码器
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Type;
@Slf4j
public class FeignDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) {
log.info("URL:[{}] response result: {}", response.request().url(), response);
return response.body();
}
}
方式1:FeignFactory.class
动态URL
import feign.*;
import java.net.URI;
public interface FeignFactory {
@RequestLine("POST {path}")
@Headers({"Content-Type: application/json", "Accept: application/json"})
<T> T doPost(URI host,@Param("path") String path, Object body);
@RequestLine("POST {path}")
<T> T doGet(URI host, @Param("path") String path);
}
工具类: FeignUtils.class
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.details.nacos.NacosFactory;
import com.details.utils.CacheUtils;
import com.details.utils.ExceptionUtils;
import com.details.utils.IocUtils;
import com.details.utils.TcpIpUtils;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import lombok.extern.slf4j.Slf4j;
import java.net.URI;
import java.util.*;
@Slf4j
public class FeignUtils {
private static Feign.Builder feignClient = null;
public static <T> T doGet(String ip, String path) {
T result = null;
ExceptionUtils.isBlank(ip, "Params :[ip] is null !");
ExceptionUtils.isBlank(ip, "Params :[path] is null !");
ExceptionUtils.isTrue(!ip.contains(":"), "Ip port not null!");
ExceptionUtils.isTrue(!ip.contains("http://"), "Ip formal error, lack \"http://\"");
try {
Feign.Builder client = feigenClient();
ExceptionUtils.isNull(client, "Feign client is null !");
client.encoder(new FeignEncoder());
client.decoder(new FeignDecoder());
client.logger(new Slf4jLogger());
client.logLevel(Logger.Level.FULL);
FeignFactory factory = client.target(FeignFactory.class, "EMPTY");
result = factory.doGet(URI.create(ip), path);
} catch (Exception e) {
log.error("HTTP get requset faild: {}", e.getMessage());
}
return result;
}
public static <T> T doPost(String ip, String path, Object body) {
T result = null;
ExceptionUtils.isBlank(ip, "Params :[ip] is null !");
ExceptionUtils.isBlank(ip, "Params :[path] is null !");
ExceptionUtils.isNull(body, "Params :[body] is null !");
ExceptionUtils.isTrue(!ip.contains(":"), "ip port not null!");
ExceptionUtils.isTrue(!ip.contains("http://"), "Ip formal error, lack \"http://\"");
try {
Feign.Builder client = feigenClient();
ExceptionUtils.isNull(client, "Feign client is null !");
client.encoder(new FeignEncoder());
client.decoder(new FeignDecoder());
client.logger(new Slf4jLogger());
client.logLevel(Logger.Level.FULL);
FeignFactory factory = client.target(FeignFactory.class, ip);
result = factory.doPost(URI.create(ip), path, body);
} catch (Exception e) {
log.error("HTTP post requset faild: {}", e.getMessage());
}
return result;
}
private static Feign.Builder feigenClient() {
try {
if (Objects.isNull(feigenClient)) {
synchronized (Feign.Builder.class) {
if (Objects.isNull(feigenClient)) {
try {
feigenClient = Feign.builder();
} catch (Exception e) {
log.error("Feigen client initialize fail: " +e.getMessage());
}
}
}
}
} catch (Exception e) {
log.error("Feigen client get faild: {}", e.getMessage());
}
return feigenClient;
}
}
方式2:FeignApiFactory.class
import feign.*;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.net.URI;
@FeignClient(value = "server-gateway", url = "EMPTY", configuration = FeignApiFactory.CallbackConfiguration.class)
public interface FeignApiFactory {
@RequestMapping(value = "{path}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
<T> T doPost(URI host, @PathVariable("path") String path, @RequestBody Object body);
@Component
class CallbackConfiguration {
@Bean
public Encoder feignEncoder() {
return new FeignEncoder();
}
@Bean
public Decoder feignDecoder() {
return new FeignDecoder();
}
@Bean
public Retryer feignRetryer() {
return new Retryer.Default();
}
@Bean
public Logger feignLogger() {
return new Slf4jLogger();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
}
|