spring?NamedContextFactory在Fegin配置及使用詳解
引言
文中代碼來(lái)源于spring-cloud的2.2.9.release版本。
1、NamedContextFactory
看一下NamedContextFactory的主要代碼。NamedContextFactory中有個(gè)contexts屬性,contexts是Map<String, AnnotationConfigApplicationContext>,這個(gè)map以name為key 以子上線文為value。
getContext方法會(huì)從contexts查找name為key的子上下文,如果沒(méi)有的話會(huì)調(diào)用createContext創(chuàng)建一個(gè)子上下文。
createContext方法是NamedContextFactory的重要方法之一。
createContext首選創(chuàng)建一個(gè)AnnotationConfigApplicationContext作為子上下文;然后查詢configurations中有無(wú)以此name為key的Specification(這個(gè)類稍后介紹),如果有相關(guān)的Specification的話就會(huì)注冊(cè)這個(gè)
Specification存儲(chǔ)的class到子上下文;
然后注冊(cè)configurations中包含的以"defalut."開(kāi)頭的key的Specification中存儲(chǔ)的class到子上下文;緊接著在子上下文注冊(cè)了PropertyPlaceholderAutoConfiguration 和 defaultConfigType(構(gòu)造方法中初始的變量);
緊接著注冊(cè)了一個(gè)名字為propertySourceName的MapPropertySource,MapPropertySource的內(nèi)容包括一個(gè)key為propertyName值為name的變量;后邊進(jìn)行設(shè)置parent然后refresh子上下文。
可以看到NamedContextFactory可以通過(guò)getContext(name)并為每個(gè)模塊構(gòu)造不同的上下文,并且加載相關(guān)的配置加載到子上下文。
使用時(shí)可以通過(guò)Specification就是存儲(chǔ)了模塊名稱和每個(gè)模塊的配置類,進(jìn)行配置,也可以通過(guò)NamedContextFactory指定一個(gè)配置類。
后邊的getInstance等方法,都是通過(guò)查詢子上下文中的來(lái)加載bean。
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware { private final String propertySourceName; private final String propertyName; private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>(); private Map<String, C> configurations = new ConcurrentHashMap<>(); private Class<?> defaultConfigType; public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) { this.defaultConfigType = defaultConfigType; this.propertySourceName = propertySourceName; this.propertyName = propertyName; } protected AnnotationConfigApplicationContext getContext(String name) { if (!this.contexts.containsKey(name)) { synchronized (this.contexts) { if (!this.contexts.containsKey(name)) { this.contexts.put(name, createContext(name)); } } } return this.contexts.get(name); } 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.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; } public <T> T getInstance(String name, Class<T> type) { AnnotationConfigApplicationContext context = getContext(name); try { return context.getBean(type); } catch (NoSuchBeanDefinitionException e) { // ignore } return null; } public void setConfigurations(List<C> configurations) { for (C client : configurations) { this.configurations.put(client.getName(), client); } } }
public interface Specification { String getName(); Class<?>[] getConfiguration(); }
2、NamedContextFactory在feign中使用
feign中提供了Specification的實(shí)現(xiàn)
class FeignClientSpecification implements NamedContextFactory.Specification { private String name; private Class<?>[] configuration; }
EnableFeignClients中import了FeignClientsRegistrar,下面代碼不是全部的EnableFeignClients代碼,做了簡(jiǎn)化處理。
@Import(FeignClientsRegistrar.class) public @interface EnableFeignClients中import了 { Class<?>[] defaultConfiguration() default {}; }
具體client的配置注冊(cè)是在FeignClientsRegistrar 實(shí)現(xiàn)的。registerBeanDefinitions方法實(shí)現(xiàn)了具體注冊(cè)。
registerDefaultConfiguration 將EnableFeignClients中的defaultConfiguration的配置,以"defalut."開(kāi)頭的名稱注入到了容器。
registerFeignClients掃描所有的@FeignClient類,得到name(具體邏輯可參考源碼),得到FeignClient的configration屬性,再調(diào)用registerClientConfiguration 就行配置(注冊(cè)了name + "." + FeignClientSpecification.class.getSimpleName()的bean)。
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); } 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()); } }
在FeignAutoConfiguration中引入了所有的 FeignClientSpecification,并且初始化了FeiginContext,調(diào)用了setConfigurations(參考NamedContextFactory方法,此操作將以name為key,F(xiàn)eignClientSpecification對(duì)象為value添加到NamedContextFactory的configurations屬性中),后續(xù)在調(diào)用到NamedContextFactory的createContext方法時(shí),會(huì)將configurations屬性中的配置進(jìn)行加載。
public class FeignAutoConfiguration { @Autowired(required = false) private List<FeignClientSpecification> configurations = new ArrayList<>(); @Bean public FeignContext feignContext() { FeignContext context = new FeignContext(); context.setConfigurations(this.configurations); return context; } }
以上就是spring NamedContextFactory在Fegin配置及使用詳解的詳細(xì)內(nèi)容,更多關(guān)于spring NamedContextFactory Fegin配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Spring Boot不同版本Redis設(shè)置JedisConnectionFactory詳解
- Spring容器-BeanFactory和ApplicationContext使用詳解
- Spring容器刷新obtainFreshBeanFactory示例詳解
- Spring擴(kuò)展BeanFactoryPostProcessor使用技巧詳解
- Spring?IOC容器FactoryBean工廠Bean實(shí)例
- 新建springboot項(xiàng)目時(shí),entityManagerFactory報(bào)錯(cuò)的解決
- 關(guān)于springboot中對(duì)sqlSessionFactoryBean的自定義
相關(guān)文章
Java使用@Autowired注解獲取對(duì)象為null的幾種情況及解決方法
這篇文章主要給大家介紹了使用@Autowired注解獲取對(duì)象為null的幾種情況以及?解決方法,文中有詳細(xì)的代碼示例講解,具有一定的參考價(jià)值,需要的朋友可以參考下2023-09-09解決idea中javaweb的mysql8.0.15配置問(wèn)題
這篇文章主要介紹了idea中javaweb的mysql8.0.15配置問(wèn)題 ,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05Java中常見(jiàn)的編碼集問(wèn)題總結(jié)
這篇文章主要為大家整理了一些Java中常見(jiàn)的編碼集問(wèn)題,文中的示例代碼講解詳細(xì),對(duì)我們深入理解Java有一定的幫助,感興趣的小伙伴可以了解一下2023-02-02服務(wù)器實(shí)現(xiàn)Java遠(yuǎn)程訪問(wèn)Linux服務(wù)器方式(JSch)
文章介紹了如何使用Java遠(yuǎn)程訪問(wèn)Linux服務(wù)器,主要包括建立SSH連接、使用JSch庫(kù)執(zhí)行命令、解析返回值以及關(guān)閉連接的步驟2024-11-11