服務調用有2種方式:rest、rpc,springcloud使用RestTemplate實作rest調用,還可以使用feign進行聲明式的遠端http服務調用,所謂聲明式就是通過服務接口來調用,和rpc相似。
使用feign進行服務調用
feign是一種服務調用方式,自然是在消費者中使用的
1、建立時勾選Spring Cloud Routing -> OpenFeign,或者手動添加依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2、引導類上加 @EnableFeignClients
//如果不指定basePackages,預設會掃描所有的包 @EnableFeignClients(basePackages = "com.chy.mall.feignclient")
在引導類上加@EnableXxx的,在啟動時會掃描相關注解。
3、建立包feignclient用來存放feign服務調用的接口
@FeignClient("order-service") //指定要調用的服務名稱。feign也内置了ribbon,會自動實作負載均衡 @RequestMapping("/order") public interface OrderServiceFeignClient { @GetMapping("/list/{user_id}") //指定位址 List<Order> findOrdersByUserId(@PathVariable("user_id") Integer userId); }
可以使用springmvc的注解綁定參數。
@FeignClient(name=“order-service”),name的别名是value,也可以寫成@FeignClient(value=“order-service”),注解特性可以預設value。
4、service
@Service public class UserService { @Autowired private OrderServiceFeignClient orderServiceFeignClient; //注入要使用的Feign接口 public List<Order> findOrdersById(Integer userId){ //通過Feign接口進行服務調用 return orderServiceFeignClient.findOrdersByUserId(userId); } }
feign的常用配置項
以feign的日志配置為例,一般的日志直接在logging.level中配置即可,feign的日志配置方式有些不同,就算把日志級别設定為debug,feign預設也不會輸出任何日志。
feign有自己的日志級别
- NONE:預設值,不列印任何日志
- BASIC: 隻列印請求方法、url、響應狀态碼、執行時間
- HEADERS:在BASIC的基礎上,會列印請求、響應的header
- FULL:列印請求、響應的header、body、中繼資料,可以看到提供者傳回的資料。
生産環境一般用BASIC,輸出日志少,性能好;開發環境一般用FULL,友善調試。
代碼配置方式
yml
logging: level: root: info #feign列印日志的前提是feign接口的日志級别是debug,因為feign輸出的日志是debug級别 com.chy.mall.feignclient: debug
配置類 config.FeignClientConfig
import feign.Logger; import org.springframework.context.annotation.Bean; /** * 定義feign接口的日志級别 * 不要加@Configuration */ public class FeignClientConfig { @Bean public Logger.Level level(){ return Logger.Level.FULL; } }
引導類
//指定feign的配置類 @EnableFeignClients(basePackages = "com.chy.mall.feignclient", defaultConfiguration = FeignClientConfig.class) //上面是全局配置,給所有的feign接口指定,也可以分别給feign接口指定 //@FeignClient("order-service", configuration = FeignClientConfig.class)
步驟也繁瑣,不推薦。
屬性配置方式(推薦)
logging: level: root: info #将feign接口的日志級别設定為debug,因為feign輸出的日志是debug級别 com.chy.mall.feignclient: debug feign: client: config: #全局配置,指定所有feign服務調用的日志級别 default: loggerLevel: full #也可以分别配置各個服務調用的 # order-server: # loggerLevel: full # msg-server: # loggerLevel: full
無需其它配置。
除了loggerLevel,feign的其它常用配置項如下
- connectTimeout: 10000 連接配接逾時時間
- readTimeout: 10000 讀取逾時時間
feign的繼承特性
提供者提供接口,消費者中有要調用的接口聲明,提供者修改了接口的映射位址、形參表、傳回值類型,比如傳回類型是實體類,現在需求變了,這個實體類要增删一些成員變量,提供者修改接口後,消費者也要同步修改,接口維護起來很麻煩。
feign的繼承特性:将要服務之間要調用的接口、涉及的實體類提出來,單獨寫成一個子產品,打成jar包在提供者、消費者中引入,然後提供者的controller實作接口,消費者的feign接口繼承接口(無需再進行聲明)。更改接口時,要稍微好維護一些。
官方不推薦使用feign的繼承特性,因為會使服務耦合在一起,但實際使用的公司也不少。
傳遞多個參數
restful适合參數少的情況,如果參數較多,可以使用以下幾種方式
- feign接口、提供者的接口都使用 @RequestParam + 多個參數
- feign接口、提供者的接口都使用 @RequestParam + Map<String,Object>
- 提供者的接口用實體類聲明參數,feign接口用 @SpringQueryMap + 實體類
第一二種都支援feign的繼承特性,第三種不支援。
不建議使用Map接收參數,需要自己轉換參數的資料類型,麻煩、易出錯。
如果把@SpringQueryMap換成@RequestParam,可以調用服務,但傳過去的實體的成員變量都是null。
脫離ribbon使用feign
ribbon是從自己的注冊中心擷取節點清單,如果是通過第三方的網關調用他們的服務,可以用HttpClient發起請求,也可以用feign發起請求,此時feign是脫離ribbon使用的。
//url指定請求位址,value指定服務名 @FeignClient(value = "xxx-server",url = "http://www.xxx.com/xxx")
服務名是必需的,如果不指定服務名,啟動不了應用。在指定了url的情況下,服務名可以随便寫一個。
feign與RestTemplate的對比
feign 僞裝、假裝,feign隻是僞rpc調用,實際使用的還是RestTemplate,使用的協定還是http。
- feign性能要低于直接使用RestTemplate。feign是将RestTemplate包裝為feign接口,生成動态代理,通過代理進行操作,有額外的開銷,拉低了性能。
- feign讓代碼可讀性更好、易于維護。服務調用接口聲明都聚集在一起,友善檢視、修改;接口改動時隻需修改feignclient包下的feign接口,無需找到所有的服務調用處,維護友善。
一般都是使用feign。
feign性能優化之配置連接配接池
feign預設使用urlconnection發起請求,不使用連接配接池;feign也支援用httpclient發起請求,可以使用feign-httpclient、okhttp等jar包提供的httpclient連接配接池。
httpclient
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
feign: #配置httpclient連接配接池 httpclient: #預設true enabled: true #feign連接配接池的最大連接配接數 max-connections: 200 #feign連接配接池單個url的最大連接配接數 max-connections-per-route: 50
這些數值都是預設值,根據壓測結果進行修改
okhttp
feign: okhttp: #預設false enabled: true #配置httpclient連接配接池 httpclient: #feign連接配接池的最大連接配接數 max-connections: 200 #feign連接配接池單個url的最大連接配接數 max-connections-per-route: 50
當然,也可以使用其它提供了httpclient連接配接池的jar包,但需要指定jar包的<version>。