在微服务架构中,如果使用得是SpringCloud,那么只需要集成SpringFeign就可以了,SpringFeign可以很友好的帮我们进行服务请求,对象解析等工作。
然而SpingCloud是依赖于SpringBoot的。在老的Spring项目中通常是没有集成SpringBoot,那么我们又该如何使用Feign组件进行调用呢?
这种情况下就只能使用原生Feign了,Feign使用手册:https://www.cnblogs.com/chenkeyu/p/9017996.html
一、原生Feign只能一次解析一个接口,生成对应的请求代理对象,如果一个包里有多个调用接口就要多次解析非常麻烦。
二、Feign生成的调用代理只是一个普通对象,该如何注册到Spring中,以便于我们可以使用@Autowired随时注入。
一、针对多次解析的问题,可以通过指定扫描包路径,然后对包中的类依次解析。使用工具:https://github.com/lukehutch/fast-classpath-scanner
二、实现BeanFactoryPostProcessor接口,扩展Spring容器功能。
com.netflix.feign feign-core 8.18.0 com.netflix.feign feign-jackson 8.18.0 io.github.lukehutch fast-classpath-scanner 2.18.1
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignApi {
String serviceUrl();
}
import feign.Feign;import feign.Request;import feign.Retryer;import feign.jackson.JacksonDecoder;import feign.jackson.JacksonEncoder;import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.stereotype.Component;import java.util.List;
@Componentpublic class FeignClientRegister implements BeanFactoryPostProcessor{ //扫描的接口路径
private String scanPath="com.xxx.api";
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
List classes = scan(scanPath); if(classes==null){ return ;
}
System.out.println(classes);
Feign.Builder builder = getFeignBuilder(); if(classes.size()>0){ for (String claz : classes) {
Class> targetClass = null; try {
targetClass = Class.forName(claz);
String url=targetClass.getAnnotation(FeignApi.class).serviceUrl(); if(url.indexOf("http://")!=0){
url="http://"+url;
}
Object target = builder.target(targetClass, url);
beanFactory.registerSingleton(targetClass.getName(), target);
} catch (Exception e) { throw new RuntimeException(e.getMessage());
}
}
}
} public Feign.Builder getFeignBuilder(){
Feign.Builder builder = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3)); return builder;
} public List scan(String path){
ScanResult result = new FastClasspathScanner(path).matchClassesWithAnnotation(FeignApi.class, (Class> aClass) -> {
}).scan(); if(result!=null){ return result.getNamesOfAllInterfaceClasses();
} return null;
}
}
import com.xiaokong.core.base.Result;import com.xiaokong.domain.DO.DeptRoom;import feign.Headers;import feign.Param;import feign.RequestLine;import com.xiaokong.register.FeignApi;import java.util.List;
@FeignApi(serviceUrl = "http://localhost:8085")public interface RoomApi {
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /room/selectById?id={id}")
Result selectById(@Param(value="id") String id);
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /room/test")
Result> selectList();
}
@Servicepublic class ServiceImpl{ //将接口注入要使用的bean中直接调用即可 @Autowired private RoomApi roomApi;
@Test public void demo(){
Result result = roomApi.selectById("1");
System.out.println(result);
}
}
1.如果接口返回的是一个复杂的嵌套对象,那么一定要明确的指定泛型,因为Feign在解析复杂对象的时候,需要通过反射获取接口返回对象内部的泛型类型才能正确使用Jackson解析。
如果不明确的指明类型,Jackson会将json对象转换成一个LinkedHashMap类型。
2.如果你使用的是的Spring,又需要通过http调用别人的接口,都可以使用这个工具来简化调用与解析的操作。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/2904/viewspace-2801667/ ,如需转载,请注明出处,否则将追究法律责任。