在微服務架構中,若是使用得是SpringCloud,那麼只須要集成SpringFeign就能夠了,SpringFeign能夠很友好的幫咱們進行服務請求,對象解析等工做。html
然而SpingCloud是依賴於SpringBoot的。在老的Spring項目中一般是沒有集成SpringBoot,那麼咱們又該如何使用Feign組件進行調用呢?java
這種狀況下就只能使用原生Feign了,Feign使用手冊:https://www.cnblogs.com/chenkeyu/p/9017996.htmlgit
1、原生Feign只能一次解析一個接口,生成對應的請求代理對象,若是一個包裏有多個調用接口就要屢次解析很是麻煩。github
2、Feign生成的調用代理只是一個普通對象,該如何註冊到Spring中,以便於咱們可使用@Autowired隨時注入。spring
1、針對屢次解析的問題,能夠經過指定掃描包路徑,而後對包中的類依次解析。使用工具:https://github.com/lukehutch/fast-classpath-scannerjson
2、實現BeanFactoryPostProcessor接口,擴展Spring容器功能。api
<dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-core</artifactId> <version>8.18.0</version> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-jackson</artifactId> <version>8.18.0</version> </dependency> <dependency> <groupId>io.github.lukehutch</groupId> <artifactId>fast-classpath-scanner</artifactId> <version>2.18.1</version> </dependency>
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 {
/**
* 調用的服務地址
* @return
*/
String serviceUrl();
}app
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; @Component public class FeignClientRegister implements BeanFactoryPostProcessor{ //掃描的接口路徑 private String scanPath="com.xxx.api"; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { List<String> 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<String> 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<DeptRoom> selectById(@Param(value="id") String id); @Headers({"Content-Type: application/json","Accept: application/json"}) @RequestLine("GET /room/test") Result<List<DeptRoom>> selectList(); }
@Service public class ServiceImpl{ //將接口注入要使用的bean中直接調用便可 @Autowired private RoomApi roomApi; @Test public void demo(){ Result<DeptRoom> result = roomApi.selectById("1"); System.out.println(result); } }
1.若是接口返回的是一個複雜的嵌套對象,那麼必定要明確的指定泛型,由於Feign在解析複雜對象的時候,須要經過反射獲取接口返回對象內部的泛型類型才能正確使用Jackson解析。dom
若是不明確的指明類型,Jackson會將json對象轉換成一個LinkedHashMap類型。
2.若是你使用的是的Spring,又須要經過http調用別人的接口,均可以使用這個工具來簡化調用與解析的操做。