重看Spring聚焦ApplicationContext分析

一、理解下ApplicationContext的设计

(一)功能性的理解

ApplicationContext 提供了一个轻量级、灵活、可扩展的容器,能帮助我们更加轻松地构建和管理复杂的应用程序,其通过依赖注入和控制反转等技术,降低了组件之间的耦合度,提高了代码的可维护性和可测试性,同时还提供了丰富的功能和扩展点可以更加灵活地满足不同项目的需求。

从基本的官方网站 Spring | Home中来重新体会的话,基本的功能性可以初步总结以下几点:

  1. Bean 实例化和管理:创建、配置和管理应用程序中的 bean 实例,可以根据配置文件或注解中的信息来实例化 bean,并且负责处理 bean 之间的依赖关系。

  2. 依赖注入(DI):支持依赖注入,即自动将 bean 之间的依赖关系注入到相应的属性中。可以通过构造函数、Setter 方法或字段注入的方式来实现依赖注入,降低组件之间的耦合度。

  3. 控制反转(IoC):实现了控制反转,即由容器负责管理组件的生命周期和依赖关系,而不是由组件自己来管理。

  4. AOP 支持:提供了对面向切面编程(AOP)的支持,可以在不修改原有代码的情况下,通过切面来实现诸如日志记录、事务管理、安全性等与业务逻辑无关的功能。

  5. 事件传播:提供了事件传播机制,允许 bean 之间进行通信,并且可以基于事件来触发特定的逻辑。使组件之间解耦更彻底,同时也提高了应用程序的可扩展性和灵活性。

  6. 国际化支持:支持国际化,允许开发人员在应用程序中使用多种语言和地区的资源。提供了统一接口来访问国际化资源,并且可根据用户的语言和地区设置动态加载相应的资源。

  7. 资源管理:不仅管理 bean,还管理应用程序中的其他资源,如消息、国际化资源、文件等。它提供了统一的接口来访问这些资源,并提供了便利的方法来加载和管理它们。

  8. 生命周期管理:负责管理 bean 的生命周期,包括实例化、初始化、销毁等过程。可以通过实现特定的接口或注解来定义 bean 的生命周期回调方法,从而在 bean 的生命周期中执行特定的逻辑。

更多理解性的内容还是通过官方文档自行体会,以上只是个人视角。

(二)ApplicationContext 结构类图

Spring Framework 中的 ApplicationContext 接口是 Spring 容器的核心接口之一,它负责管理应用程序中的 bean 并提供了各种功能。除了 ApplicationContext 接口之外,Spring 还提供了一些与其相关的子接口,这些子接口通常根据具体的使用场景和需求来扩展 ApplicationContext 的功能。

在这个类图中:

  • ApplicationContext 继承了 BeanFactory,因此拥有 BeanFactory 的功能,并增加了一些额外的特性。
  • ApplicationContext 还实现了 ApplicationEventPublisher、ResourceLoader、MessageSource 和 EnvironmentCapable 接口,提供了事件发布、资源加载、国际化消息处理和环境相关功能。
  • ApplicationContext 中的属性包括父级 ApplicationContext、BeanFactory、事件发布器、资源加载器、消息源和环境对象。
  • ApplicationContext 提供了访问这些属性的公共方法,例如获取父级 ApplicationContext、获取 BeanFactory、发布事件、获取资源加载器、获取消息源和获取环境对象等。

本文后面会针对其重要的接口和子接口进行重新的学习和总结分享。

二、ApplicationContext根接口

(一)源码展示

展示ApplicationContext 接口的部分源码,:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourceLoader {// 获取父级 ApplicationContext@NullableApplicationContext getParent();// 获取唯一 IDString getId();// 获取应用程序名称String getApplicationName();// 获取应用程序上下文显示名称String getDisplayName();// 获取启动时间long getStartupDate();// 获取所有 Bean 的名称String[] getBeanDefinitionNames();// 获取所有 Bean 的数量int getBeanDefinitionCount();// 检查是否包含指定名称的 Beanboolean containsBeanDefinition(String beanName);// 获取指定名称的 Bean 的类型@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;// 获取指定名称的 Bean 的别名String[] getAliases(String name);// 判断指定名称的 Bean 是否是单例boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 判断指定名称的 Bean 是否是原型boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 判断指定名称的 Bean 是否是当前上下文的 Beanboolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;// 判断指定名称的 Bean 是否是指定类型的 Beanboolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;// 获取指定名称的 Bean@Nullable<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;// 获取指定名称的 Bean@NullableObject getBean(String name) throws BeansException;// 获取指定类型的所有 Bean<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;// 获取指定类型的所有 Bean 的名称String[] getBeanNamesForType(@Nullable Class<?> type);// 获取指定类型的所有 Bean 的名称,包括非单例 BeanString[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);// 获取所有监听指定事件类型的监听器<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)throws BeansException;// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常<T> T getRequiredBeanOfType(@Nullable Class<T> type) throws BeansException;// 获取指定类型的 Bean 的名称,如果有多个符合条件的 Bean,则抛出异常String[] getBeanNamesForType(@Nullable ResolvableType type);// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常<T> Map<String, T> getBeansOfType(@Nullable ResolvableType type) throws BeansException;// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常<T> T getBean(Class<T> requiredType) throws BeansException;// 获取指定类型的 Bean 的名称,如果有多个符合条件的 Bean,则抛出异常String[] getBeanNamesForType(ResolvableType type);// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常<T> Map<String, T> getBeansOfType(ResolvableType type) throws BeansException;// 获取指定类型的 Bean,如果有多个符合条件的 Bean,则抛出异常<T> T getBeanProvider(Class<T> requiredType) throws BeansException;// 是否是活跃的boolean isActive();
}

可以从展示的部分直观的看到其定义了许多方法用于获取和操作 ApplicationContext 中的 bean。它继承了 EnvironmentCapable、ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ApplicationEventPublisher 和 ResourceLoader 等接口,提供了丰富的功能来管理应用程序中的 bean,并且提供了许多便捷的方法来获取 bean 的信息。

(二)分析说明

ApplicationContext 是 Spring Framework 中的核心接口之一,其提供了一种高级的容器机制,用于管理应用程序中的组件。从上面的基本源码上,我们可以提炼出以下的基本功能分析(这里不做全面的深入,因为还是太多了):

  1. Bean工厂方法: ApplicationContext 提供了丰富的方法来访问应用程序中的组件,这些方法是从 ListableBeanFactory 接口继承而来的。通过这些方法,可以方便地获取、检查和操作应用程序中的各种组件,从而实现对应用程序的灵活管理和配置。

  2. 加载文件资源: ApplicationContext 通过实现 ResourceLoader 接口,提供了一种通用的方式来加载文件资源。这些资源可以是位于类路径、文件系统、URL 等位置的文件,通过统一的接口可以方便地进行加载和访问,从而实现对应用程序资源的统一管理。

  3. 发布事件: 通过实现 ApplicationEventPublisher 接口具备了发布事件的能力,可以向注册的监听器发布事件消息,从而实现组件之间的通信和解耦。

  4. 解析消息和国际化支持: ApplicationContext 实现了 MessageSource 接口,支持消息的解析和国际化。通过 MessageSource,可以方便地在应用程序中实现多语言支持,根据不同的地区和语言加载相应的消息资源,从而提高了应用程序的可用性和用户体验。

  5. 父子上下文继承: ApplicationContext 支持从父上下文继承,子上下文中的定义优先级更高。意味着可以在整个应用程序中共享父上下文中的 bean,同时每个子上下文可以拥有自己的 bean 定义,实现更加灵活的应用程序结构。这种层级关系的管理机制使得应用程序更加模块化和可维护。

除了以上提到的功能外,ApplicationContext 还具备对应用程序中的 bean 进行生命周期管理的能力,同时可以检测和调用实现了 ApplicationContextAware、ResourceLoaderAware、ApplicationEventPublisherAware 和 MessageSourceAware 接口的 bean,使得这些 bean 可以获取对 ApplicationContext、ResourceLoader、ApplicationEventPublisher 和 MessageSource 的引用,并在运行时进行相应的操作和处理。

三、子接口ConfigurableApplicationContext

(一)源码展示

ConfigurableApplicationContext 是 ApplicationContext 接口重要的子接口,它继承了 ApplicationContext 接口,并添加了一些额外的配置功能。以下是 ConfigurableApplicationContext 接口的部分源码展示:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {// 设置应用程序上下文的 IDvoid setId(String id);// 设置应用程序名称void setApplicationName(String applicationName);// 设置父级应用程序上下文void setParent(@Nullable ApplicationContext parent);// 添加 BeanFactoryPostProcessor,用于在 bean 工厂初始化之前对 bean 定义进行后置处理void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);// 注册一个关闭钩子,用于在 JVM 关闭时关闭应用程序上下文void registerShutdownHook();// 刷新应用程序上下文,启动容器并且在必要时触发 bean 工厂后置处理器和 bean 后置处理器的注册void refresh() throws BeansException, IllegalStateException;// 关闭应用程序上下文,释放所有资源并触发 destroy 方法void close();// 销毁应用程序上下文,释放所有资源@Overridevoid destroy();// 获取环境信息@OverrideConfigurableEnvironment getEnvironment();
}

在这个接口中,可以看到一些额外的配置功能,例如设置应用程序上下文的 ID、应用程序名称、父级上下文等。另外,还提供了添加 BeanFactoryPostProcessor、注册关闭钩子、刷新和关闭应用程序上下文等方法,用于配置和管理应用程序上下文的生命周期。

注意的是,ConfigurableApplicationContext 接口继承了 Lifecycle 和 Closeable 接口,这意味着它具备了管理生命周期和关闭资源的能力。因此,任何实现了 ConfigurableApplicationContext 接口的类都应该实现这些接口中定义的方法,以确保应用程序上下文的正常运行和关闭。

(二)分析理解

ConfigurableApplicationContext 接口的设计旨在提供一种可配置的、可定制化的应用程序上下文,以满足不同场景下的需求。具体理解可以从这几个方面展开:

  1. 灵活的配置功能: ConfigurableApplicationContext 接口提供了一系列设置方法,如 setId、setApplicationName、setParent 等,用于对应用程序上下文进行配置。通过这些方法,可以灵活地配置应用程序上下文的各种属性,以满足不同应用场景下的需求。例如,可以为应用程序上下文设置唯一的 ID、指定应用程序的名称、设置父级上下文等。

  2. 后置处理器的支持: ConfigurableApplicationContext 接口提供了添加 BeanFactoryPostProcessor 的方法 addBeanFactoryPostProcessor。这意味着在应用程序上下文刷新之前,可以注册一个或多个 BeanFactoryPostProcessor,用于在 bean 工厂初始化之前对 bean 定义进行后置处理。通过这种机制,可以在容器启动之前对 bean 进行定制化的处理,例如修改 bean 的定义、添加新的 bean 定义等。

  3. 生命周期管理: ConfigurableApplicationContext 继承了 Lifecycle 接口,具备了管理生命周期的能力。它提供了刷新应用程序上下文的方法 refresh,用于启动容器并且在必要时触发 bean 工厂后置处理器和 bean 后置处理器的注册。另外,它还提供了关闭应用程序上下文的方法 close,用于释放所有资源并触发 destroy 方法。通过这些方法,可以对应用程序上下文的生命周期进行管理,确保容器的正常运行和关闭。

  4. 环境配置: ConfigurableApplicationContext 提供了获取环境信息的方法 getEnvironment,用于获取应用程序上下文的环境配置。通过环境信息,可以方便地获取应用程序的配置属性,例如配置文件中的属性、系统属性等,为应用程序的配置和定制提供了更多的灵活性和可定制性。

四、深入理解几个父接口

ConfigurableApplicationContext 是 ApplicationContext 接口重要的子接口,ApplicationContext本身还实现了几个父接口,这些父接口共同组成了ApplicationContext扩展的几个核心特性。

(一)EnvironmentCapable

EnvironmentCapable 接口的设计和实现旨在提供一种统一的方式来获取应用程序的环境配置信息,以实现组件之间的解耦合、环境配置的一致性,并且易于扩展和定制。

1.源码展示分析

EnvironmentCapable 接口定义了获取 Environment 对象的方法,是 Spring Framework 中用于获取应用程序环境配置信息的核心接口之一。以下是 EnvironmentCapable 接口的部分源码展示:

public interface EnvironmentCapable {// 获取应用程序环境对象Environment getEnvironment();
}

在这个接口中,只定义了一个方法 getEnvironment,用于获取应用程序的环境对象。Environment 对象提供了访问应用程序配置属性、系统属性、环境变量等环境信息的方法,使得应用程序可以方便地获取和管理这些配置信息。通过实现 EnvironmentCapable 接口并提供相应的实现,可以使得应用程序具备了获取环境配置信息的能力,从而可以根据不同的环境配置来调整应用程序的行为和功能。

2.理解其与ApplicationContext的关系

EnvironmentCapable 接口与 ApplicationContext 的关系在于 ApplicationContext 接口继承了 EnvironmentCapable 接口。这意味着任何实现了 ApplicationContext 接口的类都必须提供对环境配置信息的获取能力,即实现了 getEnvironment 方法

ApplicationContext 接口继承了 EnvironmentCapable 接口的原因在于,Spring 应用程序上下文需要能够获取应用程序的环境配置信息,以便于在运行时根据配置信息进行相应的操作和调整。环境配置信息可能包括应用程序的属性配置、系统属性、环境变量等。通过实现 EnvironmentCapable 接口,ApplicationContext 接口承担了获取环境配置信息的责任,使得应用程序上下文具备了对环境配置的统一访问能力。

EnvironmentCapable 接口与 ApplicationContext 的关系是一种接口继承关系,它体现了 ApplicationContext 接口对环境配置信息的依赖和需求。通过这种关系,ApplicationContext 可以通过 getEnvironment 方法获取环境配置信息,从而实现了对环境配置的统一管理和访问。

3.简单的应用举例说明

我现在有个应用程序,可能会根据不同的环境配置采取不同的行动。例如,在开发环境中,可能希望连接到本地数据库,而在生产环境中,可能希望连接到远程数据库。针对这样的需求我们就可以通过使用 EnvironmentCapable 接口和 ApplicationContext,可以轻松地实现这种行为差异。

下面是一个简单的示例,演示了如何在 Spring 应用程序中使用 EnvironmentCapable 接口和 ApplicationContext 来根据不同的环境配置加载不同的数据库连接信息:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.Environment;public class DatabaseConfigExample {public static void main(String[] args) {// 根据不同的环境加载不同的配置类ApplicationContext context = new AnnotationConfigApplicationContext(DatabaseConfig.class);// 获取 Environment 对象Environment environment = context.getEnvironment();// 从环境中获取数据库连接信息String databaseUrl = environment.getProperty("database.url");String databaseUsername = environment.getProperty("database.username");String databasePassword = environment.getProperty("database.password");// 连接到数据库System.out.println("Connecting to database:");System.out.println("URL: " + databaseUrl);System.out.println("Username: " + databaseUsername);System.out.println("Password: " + databasePassword);}
}

代码中定义了一个 DatabaseConfig 类,它根据不同的环境加载不同的数据库连接配置。然后,我们通过 ApplicationContext 获取到 Environment 对象,从中获取数据库连接信息。通过这种方式,可以根据不同的环境配置加载不同的数据库连接信息,从而实现了环境配置的灵活管理。

在实际的应用程序中,你可以将开发环境、测试环境和生产环境的配置信息分别存放在不同的配置文件中,然后通过 Spring 的配置功能来加载相应的配置文件,并根据需要获取相应的环境配置信息。这样就能够实现在不同环境下对应用程序的配置和行为进行灵活管理。

(二)MessageSource

ApplicationContext 中通常会包含一个 MessageSource 对象,用于解析和获取消息文本。通过 ApplicationContext 提供的方法,可以方便地获取 MessageSource 对象,并使用它来获取应用程序的国际化消息。这样就实现了 ApplicationContext 对国际化功能的支持和扩展。

1.源码展示分析

MessageSource 是 Spring Framework 提供的国际化支持接口,用于解析和获取消息,支持应用程序的多语言和国际化功能。以下是 MessageSource 接口的部分源码展示:

public interface MessageSource {// 根据消息的代码和参数获取对应的消息文本String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) throws NoSuchMessageException;// 根据消息的代码和参数获取对应的消息文本,如果找不到对应的消息,则返回 null@NullableString getMessage(String code, @Nullable Object[] args, Locale locale);// 根据消息的代码获取对应的消息文本,如果找不到对应的消息,则返回 null@NullableString getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

MessageSource 接口的设计和实现目的在于提供一种统一的方式来解析和获取消息文本,以支持应用程序的多语言和国际化功能。通过调用 getMessage 方法并传入相应的参数,可以根据消息的代码、参数和区域设置获取对应的消息文本,从而实现应用程序的国际化支持。

2.理解应用举例说明

实现一个简单的控制器,用于处理用户登录请求,并返回相应的消息,要求使用 MessageSource 接口来实现对登录成功和失败消息的国际化支持。

首先,我们需要在 Spring 配置文件中配置 MessageSource bean,并提供相应的消息资源文件,如 messages.properties 和 messages_zh.properties。这些文件包含了登录成功和失败消息的文本,分别对应不同的语言版本。

示例 messages.properties 文件内容如下:

login.success=Login successful.
login.error=Login failed. Please check your username and password.

示例 messages_zh.properties 文件内容如下:

login.success=登录成功。
login.error=登录失败。请检查用户名和密码。

事实上,在 Spring 应用程序中,ApplicationContext 是一个全局的容器,它在应用程序启动时被加载,并负责管理各个组件的生命周期和依赖关系。我们的控制器通常会被 Spring 容器管理,而 ApplicationContext 会自动地注入到控制器中。按当前的需求简单实现代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.Locale;@Controller
public class LoginController {@Autowiredprivate ApplicationContext applicationContext;@PostMapping("/login")@ResponseBodypublic String login(@RequestParam("username") String username, @RequestParam("password") String password) {// 假设这里进行了用户名和密码的验证boolean isAuthenticated = authenticate(username, password);if (isAuthenticated) {// 获取当前请求的语言环境Locale locale = LocaleContextHolder.getLocale();// 从 ApplicationContext 中获取 MessageSource 对象MessageSource messageSource = applicationContext.getBean(MessageSource.class);// 获取登录成功消息String successMessage = messageSource.getMessage("login.success", null, locale);return successMessage;} else {// 获取当前请求的语言环境Locale locale = LocaleContextHolder.getLocale();// 从 ApplicationContext 中获取 MessageSource 对象MessageSource messageSource = applicationContext.getBean(MessageSource.class);// 获取登录失败消息String errorMessage = messageSource.getMessage("login.error", null, locale);return errorMessage;}}private boolean authenticate(String username, String password) {// 这里省略了用户名密码验证的逻辑,简单返回 truereturn true;}
}

(三)ApplicationEventPublisher

ApplicationContext 接口继承了 ApplicationEventPublisher 接口,这意味着 ApplicationContext 具有发布事件的能力。在 Spring 应用程序中,通常会使用 ApplicationContext 来发布事件,以实现组件之间的解耦合和通信。

事件发布是 ApplicationContext 提供的一个重要功能,它允许应用程序的各个组件在适当的时候发布自定义事件,而不需要直接依赖于其他组件。通过事件驱动的方式,可以实现应用程序的松耦合,提高了代码的灵活性和可维护性。

除了作为事件发布器之外,ApplicationContext 还可以作为事件监听器(Event Listener)的容器。在 Spring 应用程序中,我们可以将事件监听器注册到 ApplicationContext 中,然后 ApplicationContext 会自动将事件分发给注册的监听器,从而实现对事件的监听和处理。

1.源码展示分析

ApplicationEventPublisher 接口是 Spring Framework 中用于发布事件的核心接口之一。以下是 ApplicationEventPublisher 接口的部分源码展示:

public interface ApplicationEventPublisher {// 发布事件void publishEvent(ApplicationEvent event);// 发布事件给指定的监听器void publishEvent(Object event);
}

在这个接口中,包含了两个发布事件的方法:

  1. publishEvent(ApplicationEvent event): 这个方法用于发布指定的应用程序事件。它接收一个 ApplicationEvent 对象作为参数,表示要发布的事件。一般情况下,我们会创建自定义的事件类,继承自 ApplicationEvent,然后通过这个方法来发布自定义事件。

  2. publishEvent(Object event): 这个方法也用于发布事件,但它接收一个任意类型的对象作为参数。Spring 会根据对象的类型来确定要发布的事件。如果对象是一个 ApplicationEvent 的子类,那么 Spring 会将其视为一个应用程序事件,并按照正常的方式进行处理。否则,Spring 会将其包装成 PayloadApplicationEvent,然后发布给监听器。

ApplicationEventPublisher 接口的设计和实现目的在于提供一种统一的方式来发布事件,以实现应用程序中各个组件之间的解耦合。通过调用 publishEvent 方法,可以将自定义事件发布给应用程序中的所有监听器,从而实现事件驱动的编程模型。

2.Spring Framework 事件驱动核心组件

Spring Framework 的事件驱动核心可以划分为以下几个主要部分:

  • 事件(Event): 事件是 Spring Framework 中的核心概念之一,代表着应用程序中发生的某个特定的动作或状态变化。事件通常被封装成一个 Java 类,实现了 ApplicationEvent 接口或其子类。Spring 提供了 ApplicationEvent 接口以及一些预定义的事件类,同时也支持开发者自定义事件类。

  • 事件发布器(Event Publisher): 事件发布器是 Spring Framework 中用于发布事件的组件。在 Spring 中,事件发布器由 ApplicationEventPublisher 接口来定义它通常由 ApplicationContext 实现。通过事件发布器,应用程序可以将事件发布到应用程序上下文中,以便监听器能够捕获并处理这些事件。

  • 事件监听器(Event Listener): 事件监听器是 Spring Framework 中用于监听和处理事件的组件。在 Spring 中,事件监听器由 ApplicationListener 接口来定义,开发者可以实现这个接口来定义自己的事件监听器。事件监听器监听特定类型的事件,当事件发生时,监听器会被调用,并执行相应的处理逻辑。

  • 事件多播器(Event Multicaster): 事件多播器是 Spring Framework 中用于将事件分发给多个监听器的组件。在 Spring 中,事件多播器由 ApplicationEventMulticaster 接口来定义,通常由 AbstractApplicationContext 实现。它负责将事件传递给所有注册的监听器,并确保它们按照特定的顺序进行调用。

  • 事件源(Event Source): 事件源是指触发事件的对象或组件。在 Spring 中,事件源通常是 ApplicationContext 或其他的 Spring Bean。当事件发生时,事件源会将事件传递给事件多播器,然后由多播器将事件分发给相应的监听器。

3.

(四)ResourcePatternResolver

(五)ResourcePatternResolver

四、

源码或官方文章

https://docs.spring.io/spring-framework/reference/core/beans/context-introduction.html

Container Overview :: Spring Framework

Spring Framework Documentation :: Spring Framework

Java-based Container Configuration :: Spring Framework

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/810584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法】统计英文字母出现的频率

题目 字母出现频率是指26英文个字母在文章中出现的频率。根据统计&#xff0c;在英语中最常出现的字母是e&#xff0c;大约占12~13%&#xff0c;出现最少的字母是z&#xff0c;不到0.1% &#xff0c;如下图所示&#xff08;统计结果来自wiki百科&#xff09; 字母出现频率的统…

三方库移植之NAPI开发(三)通过IDE开发NAPI工程

在三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI一文中&#xff0c;笔者开发的是一个rom包的napi工程。该工程需要编译烧录固件&#xff0c;C 的动态库会集成到开发板的ROM中。在本篇文章中&#xff0c;笔者使用三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI中一样的he…

VXWorks6.9 + Workbench3.3 开发环境部署

VxWorks系列传送门 一、安装包 有需要的朋友可以私信~ 二、安装 安装挺简单 1、先安装DVD-R147826.1-1-01-vx69.udf.iso 镜像中的Setup.exe程序&#xff0c;记住要使用管理员权限 2、再安装DVD-R147826.1-23-00.iso 镜像中的Setup.exe程序&#xff0c;同样要使用管理员权限 3…

基于大数据的汽车信息可视化分析预测与推荐系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 本项目通过集成网络爬虫技术&#xff0c;实时获取海量汽车数据&#xff1b;运用先进的ARIMA时序建模算法对数据进行深度挖掘和分析&#xff1b;结合flask web系统和echarts可视化工具&#xff0c;…

CF698B Fix a Tree 题解 贪心

Fix a Tree 传送门 A tree is an undirected connected graph without cycles. Let’s consider a rooted undirected tree with n n n vertices, numbered 1 1 1 through n n n . There are many ways to represent such a tree. One way is to create an array with n…

基于GitHub的开源讨论系统,赋予网站交互可能

Giscus&#xff1a;让每一条见解直达GitHub&#xff0c;用Giscus开启网站与社区的无缝对话新纪元&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 纯静态网站或博客&#xff0c;由于没有数据存储功能&#xff0c;经常借助第三方的评论系统以插件的方式集成进来&#x…

uniapp 编译后分包下静态图片404问题解决方案

如上图官方说明&#xff1a; 在分包下建立一个static文件夹即可&#xff1a; 分包内代码引用图片 <image src"/分包名称/img/图片名称"></image> <image src"/dataView/img/图片名称"></image>

SQL执行流程图文分析:从连接到执行的全貌

SQL执行总流程 下面就是 MySQL 执行一条 SQL 查询语句的流程&#xff0c;也从图中可以看到 MySQL 内部架构里的各个功能模块。 MySQL 的架构共分为两层&#xff1a;Server 层和存储引擎层&#xff0c; Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在…

Navicat连接SQL server出现:[IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序(0)

问题 解决方法 一 找到Navicat的安装路径&#xff0c;然后找到sqlncli_x64.msi文件并安装&#xff0c;安装成功后重启Navicat重新进行连接&#xff0c;看是否成功。 解决方法 二 如果方法一没有找到找到sqlncli_x64.msi 还是Navicat的安装路径&#xff0c;然后找到msodbcsql_64…

03-JAVA设计模式-适配器模式

适配器模式 设么是适配器模式 它属于结构型模式&#xff0c;主要用于将一个类的接口转换成客户端所期望的另一种接口&#xff0c;从而使得原本由于接口不兼容而无法协同工作的类能够一起工作。 适配器模式主要解决的是不兼容接口的问题。在软件开发中&#xff0c;经常会有这…

第三十八节 Java 多线程编程

Java 给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程&#xff0c;并且每个线程定义了一个独立的执行路径。 多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。 这里定义和线程相关的另一个术语&…

【错误分享】打开Qt编译生成的软件,“无法找到入口”

错误简介 这张图片显示的是一个计算机错误提示窗口&#xff0c;标题为“无法找到入口”。正文内容是&#xff1a;“无法定位程序输入点_Z21qRegisterResourceDataaiPKhS0_S0_于动态链接库Qt5Core.dll上。” 这意味着在尝试运行程序时遇到了问题。 具体来说&#xff0c;该错误表…

Vue内置组件Transition用法介绍

Vue 提供了两个内置组件&#xff0c;可以帮助你制作基于状态变化的过渡和动画&#xff1a; <Transition> 会在一个元素或组件进入和离开 DOM 时应用动画。本章节会介绍如何使用它。 <TransitionGroup> 会在一个 v-for 列表中的元素或组件被插入&#xff0c;移动&a…

从大量数据到大数据,King’s SDMS仪器数据采集及科学数据管理系统的应用

对于实验室或检测机构&#xff0c;仪器设备是所有业务开展的基础&#xff0c;数据则是核心命脉&#xff0c;而传统的仪器设备原始数据收集方式&#xff0c;效率低耗时长、操作流程不规范、不易保存与查找、错误率高、易篡改等成了制约检测机构持续高速发展的瓶颈和弊端&#xf…

单例19c RMAN数据迁移方案

一、环境说明 源库 目标库 IP 192.168.37.200 192.168.37.202 系统版本 RedHat 7.9 RedHat 7.9 数据库版本 19.3.0.0.0 19.3.0.0.0 SID beg beg hostname beg rman 数据量 1353M 说明:源库已经创建数据库实例&#xff0c;并且存在用户kk和他创建的表空间…

新规来了!智能音视频技术重塑信贷体验

近日&#xff0c;国家金融监督管理总局发布《固定资产贷款管理办法》《流动资金贷款管理办法》《个人贷款管理办法》&#xff08;以下简称“三个办法”&#xff09;。 具体来看&#xff0c;新规明确了以下要求&#xff1a; 1、明确视频面签、电子签约要求 允许商业银行通过视…

Oracle 19c RAC集群相关日志

1.DB日志&#xff08;数据库日志&#xff09; Redo Log&#xff08;重做日志&#xff09;&#xff1a; 在Oracle数据库中&#xff0c;重做日志记录了数据库发生的所有修改操作&#xff0c;包括数据的插入&#xff0c;更新和删除。在RAC的环境中&#xff0c;每个实例都有自己的重…

Ubuntu22.04搭建CLion C++开发环境

Ubuntu22.04搭建CLion C开发环境 文章目录 Ubuntu22.04搭建CLion C开发环境1.首先下载CLion2.配置c环境3.创建快捷方式Reference 1.首先下载CLion 进入官网https://www.jetbrains.com/clion/download/#sectionlinux 然后进入自己存放这个压缩包的路径中&#xff0c; sudo mkd…

SQLite从出生到现在(发布历史记录)(二十二)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;从 SQLite 3.5.9 迁移到 3.6.0&#xff08;二十一&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 引言&#xff1a; SQLite拥有别人无法比拟的装机量&#xff0c;究竟什么成就了SQLite呢&#xff0c;本…

最长公共子序列、最长上升子序列(LCS与LIS)算法

最长公共子序列、最长上升子序列(LCS与LIS) 最长公共子序列(LCS) #include <bits/stdc.h> using namespace std; #define int long long const int N 1e39; int a[N],b[N],dp[N][N]; signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int n,m;cin>>…