由上文咱們知道針對某一個Feign接口,咱們能夠給他設置特定的配置類。那若是如今有一個服務,咱們只想對A服務配置一個攔截器攔截請求而不影響其餘服務,那應該怎麼作呢?git
由前面的文章咱們知道了feign的代理過程以及調用過程。如今咱們看一下feign都有哪些配置?github
屬性 | 值類型 | 含義 |
---|---|---|
value | string | 服務名,不管是否有URL,服務名稱都不能爲空,它能夠設置爲屬性值${server_name}這種形式 |
name | string | 同value |
qualifier | string | 指定feign接口在容器中的bean實例名稱(咱們知道每個feign接口最終都會向容器注入一個實例),等同於@Qualifier |
url | string | 絕對URL或可解析主機名(協議是可選的) |
decode404 | boolean | 是否應該解碼404而不是拋出假異常 |
fallback | class | 指定一個會退類(好比發生未處理的異常後)。回退類必須實現feign接口,並註冊到容器。 |
fallbackFactory | class | 爲指定的外部客戶機接口定義回退工廠。回退工廠必須實現FallbackFactory接口,此工廠接口返回一個feign接口對應的回滾類。回退工廠必須註冊到容器。 |
path | string | 指定相對路徑 |
primary | boolean,默認true | 當容器中存在同名的bean的實現,以當前代理對象的bean爲主。 |
configuration | class | 當前feign接口的配置類,他會將配置類註冊到當前feign對象的容器中(非應用程序的上下文環境) |
這裏直接上核心代碼(FeignClientsRegistrar.registerClientConfiguration)spring
// name @FeignClient的name屬性值 // configuration @FeignClient的class對象 private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition( name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
由上面的代碼咱們知道,他是將@FeignClient對象的configuration屬性對應的配置類做爲成員FeignClientSpecification的屬性注入到應用上下文。那看到這裏咱們就會產生一個疑問:configuration對應的配置類到底何時被初始化呢?最終發如今爲@FeignClient生成代理對象的時候,他初始化了FeignClient對應的配置。以下(NamedContextFactory.createContext):安全
// 在獲取一個@FeignClient接口對應的代理對象前,先爲其建立Context對象 protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); if (this.configurations.containsKey(name)) { for (Class<?> configuration : this.configurations.get(name) .getConfiguration()) { // 註冊配置 context.register(configuration); } } for (Map.Entry<String, C> entry : this.configurations.entrySet()) { if (entry.getKey().startsWith("default.")) { for (Class<?> configuration : entry.getValue().getConfiguration()) { // 註冊配置 context.register(configuration); } } } context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); // 爲context註冊環境變量 context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( this.propertySourceName, Collections.<String, Object>singletonMap(this.propertyName, name))); if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); // jdk11 issue // https://github.com/spring-cloud/spring-cloud-netflix/issues/3101 context.setClassLoader(this.parent.getClassLoader()); } context.setDisplayName(generateDisplayName(name)); context.refresh(); return context; }
顯然,在爲@FeignClient接口的代理對象建立了Context後,將配置初始化到了該Context。這裏能夠明確的是每個@FeignClient只要name屬性不一致,那麼他們將擁有不一樣的上下文。網絡
在現實中的sandbox,是一種兒童玩具,類如KFC中一個裝滿小球的容器,兒童能夠在隨意玩耍,起到保護兒童的做用。(也能夠理解爲一種安全環境)。一樣在網絡技術中也是一種按照安全策略限制程序行爲的執行環境。在feign的調用過程當中,針對不一樣的服務爲其建立一個上下文,咱們能夠將這個上下文理解爲sandbox。執行調用所須要的資源是從各自的沙箱環境中取。總體的職責分工以下圖所示。
框架
從中咱們能夠看到,咱們最終調用的執行器來源是來自沙箱,而沙箱的配置能夠各不相同,建立不一樣的Client,這給了咱們決定不一樣的服務怎樣去調用高度的自主權。也解決了文章開篇提出的問題。ui
至此,feign調用暫時告一段落。因爲後續要花時間作一個開源框架,文章的書寫便只能告一段落了。this