天天看點

SpringCloud進階-詳解如何使用Feign實作服務接口調用

作者:架構師面試寶典
SpringCloud進階-詳解如何使用Feign實作服務接口調用

Fegin是一個聲明式的REST調用的用戶端,使用Fegin會讓REST接口的調用變得更加簡單。它提供了各種的HTTP請求模闆幾乎可以适用于各種接口的調用,通過編寫簡單的接口調用方式添加簡單的注解就可以将HTTP的請求、參數、位址、格式等内容進行設定。

Fegin會完全的代理HTTP請求,使用的時候直接調用對應的方法就可以實作接口的服務請求相關處理。

在Spring Cloud中對于Fegin進行了像是Ribbon一樣的封裝處理。它支援Spring MVC的各種調用标準和注解标準。可以與Eureka和Ribbon有機的整合實作接口調用和負載均衡等操作。下面我們就來看看在Spring Cloud中如何整合一個Feign。

Spring Cloud中內建Fegin

我們需要在建立的Spring Cloud項目中添加Fegin相關的依賴。在POM檔案中添加如下的依賴配置。

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>           

在添加完相應的配置之後,我們需要在應用的主啟動類上添加一個@EnableFeignClients注解用來表示這個應用是一個Fegin的的用戶端操作。當然也可以在這個注解的basePackages屬性中傳入需要被掃描的Fegin用戶端存在的包路徑。

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}           

可以看到我們在啟動類上還添加了@EnableDiscoveryClient注解,表示将這個應用以服務的形式注入的Eureka注冊中心。來提供其他服務的調用,或者是用來調用其他服務。

如何使用Feign實作接口的調用呢?

首先我們需要知道如何去定義一個Fegin的接口調用。我們可以通過@FeignClient注解來指定這個是一個Fegin的調用用戶端操作,代碼如下。

@FeignClient(value="eureka-client-user-service")
public interface UserRemoteClient {

   @GetMapping("/hello") 
   String hello();
   
}
           

其中value屬性指定的值就是我們在Eureka服務注冊中心中設定的服務名稱,也就是你需要調用哪個服務的接口。

UserRemoteClient 是一個接口類,也就是說在這個類中我們隻需要定義一些關于如何調用使用者服務的接口規則,具體的調用操作則交給了使用的時候的Controller層,代碼如下

@RestController
public class DemoController {

	@Autowired
	private UserRemoteClient userRemoteClient;

	@GetMapping("/getUserInfo")
	public String callHello() {
		String result = userRemoteClient.hello();
		System.out.println(" 調用結果:" + result);
		return result;
	}

}           

從代碼中,我們可以看到,代碼中并沒有像是RestTemplate一樣的調用設定,而是直接使用userRemoteClient.hello()方式進行了接口調用。就如同直接調用了使用者服務一樣。那麼我們的Spring Cloud究竟是如何實作對于Feign的管理調用的呢?下面我們就來看一下Fegin的調用原理

Fegin調用原理

首先我們需要關注在上面提到的一個注解@EnableFeignClients,在這個注解的源碼中我們會看到如下的一些資訊。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
}           

會看到使用了@Import的方式引入了一個FeignClientsRegistrar的類,這個類主要就是用來完成對于@FeginClient注解标注類進行容器注入操作。其中比較關鍵的就是如下的兩個方法

  • public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry)
  • private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes)

這兩個方法幾乎完成了所有的被标注了@FeginClient注解的類到HTTP請求方法的轉換操作。例如其中有如下的代碼

private String getUrl(Map<String, Object> attributes) {
		String url = resolve((String) attributes.get("url"));
		return getUrl(url);
	}

	static String getUrl(String url) {
		if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) {
			if (!url.contains("://")) {
				url = "http://" + url;
			}
			try {
				new URL(url);
			}
			catch (MalformedURLException e) {
				throw new IllegalArgumentException(url + " is malformed", e);
			}
		}
		return url;
	}           

等到完成這些操作之後,其實容器中存在的就是類似于一系列的REST接口調用的執行個體對象,然後結合之前Ribbon中所講的内容,我們知道在注冊中心中有各種服務的清單。而服務調用者在調用的時候會有這些服務的所有清單,可以從這個清單中根據自己的規則來找到自己對應需要調用的服務。

而根據上面的操作我們可以知道,在配置了FeginClient之後,會将所有的服務都進行封裝,我們隻需要根據定義好的規則來進行調用即可,就像是上面代碼中在Controller中寫的一樣。

總結

在我們傳統的調用中對于一些需要進行配置的内容都需要我們自己編寫代碼來實作,而使用了Fegin之後這些操作都可以在注入的時候通過前置處理器進行提前的配置,簡化了調用的時候的重複代碼編寫工作。