[spring-cloud: NamedContextFactory ClientFactoryObjectProvider]-源碼閱讀

依賴

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-commons</artifactId><version>4.3.0</version>
</dependency>

源碼

NamedContextFactory

NamedContextFactory 類通過創建多個子上下文并為每個子上下文定義不同的配置,提供了靈活的 Spring 上下文管理方式。

/*** Creates a set of child contexts that allows a set of Specifications to define the beans* in each child context. Ported from spring-cloud-netflix FeignClientFactory and* SpringClientFactory** @param <C> specification* @author Spencer Gibb* @author Dave Syer* @author Tommy Karlsson* @author Olga Maciaszek-Sharma*/
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware {// 子容器初始化private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;private final String propertySourceName;private final String propertyName;// 子容器集合private final Map<String, GenericApplicationContext> contexts = new ConcurrentHashMap<>();// 子容器配置private final Map<String, C> configurations = new ConcurrentHashMap<>();// 父容器private ApplicationContext parent;private final Class<?> defaultConfigType;public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {this(defaultConfigType, propertySourceName, propertyName, new HashMap<>());}public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {this.defaultConfigType = defaultConfigType;this.propertySourceName = propertySourceName;this.propertyName = propertyName;this.applicationContextInitializers = applicationContextInitializers;}@Overridepublic void setApplicationContext(ApplicationContext parent) throws BeansException {this.parent = parent;}public ApplicationContext getParent() {return parent;}public void setConfigurations(List<C> configurations) {for (C client : configurations) {this.configurations.put(client.getName(), client);}}public Set<String> getContextNames() {return new HashSet<>(this.contexts.keySet());}@Overridepublic void destroy() {Collection<GenericApplicationContext> values = this.contexts.values();for (GenericApplicationContext context : values) {// This can fail, but it never throws an exception (you see stack traces// logged as WARN).context.close();}this.contexts.clear();}protected GenericApplicationContext 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);}public GenericApplicationContext createContext(String name) {GenericApplicationContext context = buildContext(name);// there's an AOT initializer for this contextif (applicationContextInitializers.get(name) != null) {applicationContextInitializers.get(name).initialize(context);context.refresh();return context;}registerBeans(name, context);context.refresh();return context;}public void registerBeans(String name, GenericApplicationContext context) {Assert.isInstanceOf(AnnotationConfigRegistry.class, context);AnnotationConfigRegistry registry = (AnnotationConfigRegistry) context;if (this.configurations.containsKey(name)) {for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {registry.register(configuration);}}for (Map.Entry<String, C> entry : this.configurations.entrySet()) {if (entry.getKey().startsWith("default.")) {for (Class<?> configuration : entry.getValue().getConfiguration()) {registry.register(configuration);}}}registry.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);}// 根據指定名稱創建并配置一個 GenericApplicationContext,并根據父上下文、AOT 支持等條件動態選擇上下文實現。public GenericApplicationContext buildContext(String name) {// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101// https://github.com/spring-cloud/spring-cloud-openfeign/issues/475ClassLoader classLoader = getClass().getClassLoader();GenericApplicationContext context;if (this.parent != null) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();if (parent instanceof ConfigurableApplicationContext) {beanFactory.setBeanClassLoader(((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());}else {beanFactory.setBeanClassLoader(classLoader);}context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext(beanFactory) : new AnnotationConfigApplicationContext(beanFactory);}else {context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext() : new AnnotationConfigApplicationContext();}context.setClassLoader(classLoader);context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName, Collections.singletonMap(this.propertyName, name)));if (this.parent != null) {// Uses Environment from parent as well as beanscontext.setParent(this.parent);}context.setDisplayName(generateDisplayName(name));return context;}protected String generateDisplayName(String name) {return this.getClass().getSimpleName() + "-" + name;}public <T> T getInstance(String name, Class<T> type) {GenericApplicationContext context = getContext(name);try {return context.getBean(type);}catch (NoSuchBeanDefinitionException e) {// ignore}return null;}public <T> ObjectProvider<T> getLazyProvider(String name, Class<T> type) {return new ClientFactoryObjectProvider<>(this, name, type);}public <T> ObjectProvider<T> getProvider(String name, Class<T> type) {GenericApplicationContext context = getContext(name);return context.getBeanProvider(type);}public <T> T getInstance(String name, Class<?> clazz, Class<?>... generics) {ResolvableType type = ResolvableType.forClassWithGenerics(clazz, generics);return getInstance(name, type);}@SuppressWarnings("unchecked")public <T> T getInstance(String name, ResolvableType type) {GenericApplicationContext context = getContext(name);String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type);for (String beanName : beanNames) {if (context.isTypeMatch(beanName, type)) {return (T) context.getBean(beanName);}}return null;}@SuppressWarnings("unchecked")public <T> T getAnnotatedInstance(String name, ResolvableType type, Class<? extends Annotation> annotationType) {GenericApplicationContext context = getContext(name);String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(context, annotationType);List<T> beans = new ArrayList<>();for (String beanName : beanNames) {if (context.isTypeMatch(beanName, type)) {beans.add((T) context.getBean(beanName));}}if (beans.size() > 1) {throw new IllegalStateException("Only one annotated bean for type expected.");}return beans.isEmpty() ? null : beans.get(0);}public <T> Map<String, T> getInstances(String name, Class<T> type) {GenericApplicationContext context = getContext(name);return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);}public Map<String, C> getConfigurations() {return configurations;}/*** Specification with name and configuration.*/public interface Specification {String getName();Class<?>[] getConfiguration();}}

ClientFactoryObjectProvider

ClientFactoryObjectProvider 是一個特殊的 ObjectProvider,它通過延遲解析實際的 ObjectProvider,以便在創建命名的子上下文后再解析對象。

class ClientFactoryObjectProvider<T> implements ObjectProvider<T> {private final NamedContextFactory<?> clientFactory;private final String name;private final Class<T> type;private ObjectProvider<T> provider;ClientFactoryObjectProvider(NamedContextFactory<?> clientFactory, String name, Class<T> type) {this.clientFactory = clientFactory;this.name = name;this.type = type;}@Overridepublic T getObject(Object... args) throws BeansException {return delegate().getObject(args);}@Override@Nullablepublic T getIfAvailable() throws BeansException {return delegate().getIfAvailable();}@Overridepublic T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {return delegate().getIfAvailable(defaultSupplier);}@Overridepublic void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {delegate().ifAvailable(dependencyConsumer);}@Override@Nullablepublic T getIfUnique() throws BeansException {return delegate().getIfUnique();}@Overridepublic T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {return delegate().getIfUnique(defaultSupplier);}@Overridepublic void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {delegate().ifUnique(dependencyConsumer);}@Overridepublic Iterator<T> iterator() {return delegate().iterator();}@Overridepublic Stream<T> stream() {return delegate().stream();}@Overridepublic T getObject() throws BeansException {return delegate().getObject();}@Overridepublic void forEach(Consumer<? super T> action) {delegate().forEach(action);}@Overridepublic Spliterator<T> spliterator() {return delegate().spliterator();}private ObjectProvider<T> delegate() {if (this.provider == null) {this.provider = this.clientFactory.getProvider(this.name, this.type);}return this.provider;}}

實現

推薦閱讀:[spring-cloud: @LoadBalanced & @LoadBalancerClient]-源碼分析

LoadBalancerClientFactory & LoadBalancerClientSpecification

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917656.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917656.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917656.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HBase MOB技術特點及使用場景介紹

在 HBase 2.0 版本之前,雖然 HBase 能夠存儲從 1 字節到 10MB 大小的二進制對象 ,但其讀寫路徑主要針對小于 100KB 的值進行了優化。當面對大量大小在 100KB - 10MB 之間的數據時,傳統的存儲方式就會暴露出問題。例如,當存儲大量的圖片、文檔或短視頻等中等大小對象時,由于…

Ubuntu 配置密鑰+密碼登錄

目錄 1、密鑰生成 2、發送公鑰至 需要連接的服務器 3、選用私鑰登錄 1、密鑰生成 ssh-keygen -t rsa -b 4096 -C "angindem"2、發送公鑰至 需要連接的服務器 將.ssh中的id_rsa.pub 的密鑰&#xff0c;放在authorized_keys中 注意&#xff1a;.ssh 文件夾一定賦予…

谷歌瀏覽器Chrome 緩存遷移

步驟 1&#xff1a;準備數據遷移1. 關閉 Chrome 及所有后臺進程在任務管理器&#xff08;CtrlShiftEsc&#xff09;中結束所有 chrome.exe 進程。 2. 備份并移動原數據- 將 C:\Users\xxx\AppData\Local\Google\Chrome\User Data **整個文件夾**復制到新位置&#xff08;如 G:\…

Java中的RabbitMQ完全指南

Java中的RabbitMQ完全指南 1. 引言 什么是RabbitMQ RabbitMQ是一個開源的消息代理和隊列服務器&#xff0c;實現了高級消息隊列協議&#xff08;AMQP&#xff09;。它充當應用程序之間的消息中間件&#xff0c;允許分布式系統中的不同組件進行異步通信。RabbitMQ使用Erlang語言…

【MCAL】AUTOSAR架構下SPI數據異步DMA收發具體實現

目錄 前言 正文 1.依賴的硬件特性 1.1.SPI硬件特性 1.1.1. TXFIFO Single Move Mode 1.1.2. RXFIFO Single Move Mode 1.1.3. Move Counter模式 1.1.4. PT中斷 1.2.IR硬件特性 1.3.DMA硬件特性 1.3.1. DMA通道硬件請求 1.3.2. DMA循環Buffer 1.3.3. DMA Link List …

【Unity】協程 Async

協程 協程是 Unity 內置的異步機制&#xff0c;通過 yield 暫停執行&#xff0c;實現任務在多幀中分段執行。與普通函數不同&#xff0c;協程可在執行過程中掛起和恢復&#xff0c;呈現"并發"效果&#xff0c;但本質上仍運行于主線程。若在協程中進行耗時操作&#…

《揭秘!10 分鐘洞悉 Prompt、Function Calling、MCP 與 AI agent 奧秘》

Prompt、Function Calling、MCP、AI agent這些術語頻繁闖入我們的視野&#xff0c;它們到底都是什么、有啥關系。只需十分鐘&#xff0c;咱們抽絲剝繭&#xff0c;揭開它們的神秘面紗&#xff0c;輕松掌握這些關鍵概念 并了解AI agent 完整執行流程。 一、提示詞&#xff08;P…

決策樹(回歸樹)全解析:原理、實踐與應用

文章目錄一、概述1.1 介紹1.2 回歸樹和分類樹區別二、重要參數、屬性及接口2.1 criterion&#xff08;不純度衡量指標&#xff09;2.2 回歸樹如何工作&#xff08;核心流程拆解&#xff09;三、用回歸樹擬合正弦曲線&#xff08;實戰案例&#xff09;3.1 繪制正弦曲線3.2 為正弦…

【盤古100Pro+開發板實驗例程】FPGA學習 | HDMI 回環實驗

本原創文章由深圳市小眼睛科技有限公司創作&#xff0c;版權歸本公司所有&#xff0c;如需轉載&#xff0c;需授權并注明出處&#xff08;www.meyesemi.com) 1. 實驗簡介 實驗目的&#xff1a; 完成 HDMI 回環實驗 實驗環境&#xff1a; Window11 PDS2022.2-SP6.4 硬件環境…

鴻蒙系統PC安裝指南

鴻蒙系統PC安裝指南一、安裝DevEco Studio集成開發環境二、下載鴻蒙系統PC三、啟動鴻蒙系統及使用一、安裝DevEco Studio集成開發環境首先訪問華為官網上&#xff0c;注冊并登錄華為賬號&#xff0c;以開始下載所需的軟件。若尚未注冊&#xff0c;請先注冊一個。在官網頁面中&a…

三十九、【擴展工具篇】Allpairspy 組合用例生成器:智能設計高效測試集

三十九、【擴展工具篇】Allpairspy 組合用例生成器:智能設計高效測試集 前言 準備工作 第一部分:后端實現 - `allpairspy` API 1. 創建 `allpairspy` 服務 2. 創建 `allpairspy` API 視圖 3. 注冊 API 路由 第二部分:前端實現 - `Allpairspy` 工具界面 1. 創建 API 服務 (`s…

ZooKeeper 深度實踐:從原理到 Spring Boot 全棧落地

在 Kubernetes 為主流注冊發現的今天&#xff0c;給出如何在 Spring Boot 中基于 ZooKeeper 實現服務注冊/發現、分布式鎖、配置中心以及集群協調的完整代碼與最佳實踐。所有示例均可直接復制運行。 1. ZooKeeper 架構與核心原理 1.1 角色 Leader&#xff1a;處理寫請求&…

可驗證隨機函數-VRF

可驗證隨機函數&#xff08;Verifiable Random Function, VRF&#xff09;是一種結合密碼學技術的偽隨機數生成器&#xff0c;其核心特點是生成的隨機數可被公開驗證&#xff0c;且具有不可預測性和唯一性。以下是VRF的詳細解析&#xff1a;1. 基本定義與核心特性 可驗證性&…

極客大挑戰2020(部分wp)

Roamphp1-Welcome 405請求方法不允許&#xff0c;改一下請求方法 數組繞過&#xff0c;在頁面搜索flag即可&#xff01;本題&#xff1a;就是知道了405是請求方法不允許&#xff01; Roamphp2-Myblog&#xff08;zip協議加文件包含&#xff09; 首先進來就是一個博客頁面&…

ESP32 外設驅動開發指南 (ESP-IDF框架)——GPIO篇:基礎配置、外部中斷與PWM(LEDC模塊)應用

目錄 一、前言 二、GPIO 2.1 GPIO簡介 2.2 GPIO函數解析 2.3 LED驅動 2.4 KEY驅動 三、EXIT 3.1 EXIT簡介 3.2 EXIT函數解析 3.3 EXIT驅動 四、LEDC 4.1 PWM原理解析 4.2 ESP32的LED PWM控制器介紹 4.3 LEDC函數解析 4.3.1 SW_PWM 4.3.2 HW_PWM 4.4 LEDC驅動 …

鴻蒙 ArkWeb 加載優化方案詳解(2025 最佳實踐)

適用平臺&#xff1a;HarmonyOS NEXT / API 10 關鍵詞&#xff1a;ArkWeb、WebviewController、NodeController、預加載、預連接、預渲染、性能優化一、前言&#xff1a;為什么必須優化 ArkWeb 加載&#xff1f;在鴻蒙生態中&#xff0c;ArkWeb 是系統級的 Web 容器引擎&#x…

JavaScript案例(乘法答題游戲)

項目概述 使用原生JavaScript實現一個乘法答題游戲&#xff0c;隨機生成乘法題目&#xff0c;判斷答案正誤并記錄分數&#xff0c;通過localStorage實現分數持久化存儲。 核心功能需求 隨機題目生成&#xff1a;動態生成1-10之間的乘法題答題交互&#xff1a;輸入答案并提交…

EXCEL刪除數據透視表

wps版 點擊紅框內任意區域 在頂部工具欄選擇刪除Excel 版 1.點擊紅框內任意區域2. 點擊Enable Selection,再按住鍵盤上的Delete鍵&#xff0c;記住不是Backspace鍵

Python 飛機大戰:從零開發經典 2D 射擊游戲

引言&#xff1a;重溫經典游戲開發 飛機大戰作為經典的 2D 射擊游戲&#xff0c;承載了許多人的童年回憶。使用 Python 和 Pygame 開發這樣一款游戲不僅能重溫經典&#xff0c;更是學習游戲開發絕佳的實踐項目。本文將帶你從零開始&#xff0c;一步步實現一個完整的飛機大戰游…

Vue項目中實現瀏覽器串口通信:Web Serial API完整指南

前言 在現代Web開發中&#xff0c;隨著IoT設備和硬件交互需求的增長&#xff0c;瀏覽器與串口設備的通信變得越來越重要。本文將詳細介紹如何在Vue項目中使用Web Serial API實現串口通信功能&#xff0c;為開發者提供一個完整的解決方案。 技術背景 傳統方案的局限性 傳統的串口…