重看Spring聚焦ApplicationContext分析

news2024/11/23 0:37:44

一、理解下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
    @Nullable
    ApplicationContext getParent();
    
    // 获取唯一 ID
    String getId();
    
    // 获取应用程序名称
    String getApplicationName();
    
    // 获取应用程序上下文显示名称
    String getDisplayName();
    
    // 获取启动时间
    long getStartupDate();
    
    // 获取所有 Bean 的名称
    String[] getBeanDefinitionNames();
    
    // 获取所有 Bean 的数量
    int getBeanDefinitionCount();
    
    // 检查是否包含指定名称的 Bean
    boolean containsBeanDefinition(String beanName);
    
    // 获取指定名称的 Bean 的类型
    @Nullable
    Class<?> 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 是否是当前上下文的 Bean
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    
    // 判断指定名称的 Bean 是否是指定类型的 Bean
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    
    // 获取指定名称的 Bean
    @Nullable
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    
    // 获取指定名称的 Bean
    @Nullable
    Object getBean(String name) throws BeansException;
    
    // 获取指定类型的所有 Bean
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    
    // 获取指定类型的所有 Bean 的名称
    String[] getBeanNamesForType(@Nullable Class<?> type);
    
    // 获取指定类型的所有 Bean 的名称,包括非单例 Bean
    String[] 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 {

    // 设置应用程序上下文的 ID
    void 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();

    // 销毁应用程序上下文,释放所有资源
    @Override
    void destroy();

    // 获取环境信息
    @Override
    ConfigurableEnvironment 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
    @Nullable
    String getMessage(String code, @Nullable Object[] args, Locale locale);

    // 根据消息的代码获取对应的消息文本,如果找不到对应的消息,则返回 null
    @Nullable
    String 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 {

    @Autowired
    private ApplicationContext applicationContext;

    @PostMapping("/login")
    @ResponseBody
    public 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) {
        // 这里省略了用户名密码验证的逻辑,简单返回 true
        return 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.coloradmin.cn/o/1588763.html

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

相关文章

2024年第五届计算机视觉与信息技术国际会议(CVIT 2024)即将召开!

2024年第五届计算机视觉与信息技术国际会议&#xff08;CVIT 2024&#xff09;将于2024年8月16-18日在北京举行。CVIT 2024由北方工业大学主办&#xff0c;国内外的专家学者将齐聚一堂&#xff0c;共同分享最新的技术突破、研究方法和应用案例&#xff0c;共同推动计算机视觉与…

LeetCode-62. 不同路径【数学 动态规划 组合数学】

LeetCode-62. 不同路径【数学 动态规划 组合数学】 题目描述&#xff1a;解题思路一&#xff1a;动态规划&#xff0c;动规五部曲解题思路二&#xff1a;动态规划&#xff08;版本二&#xff09;解题思路三&#xff1a;数论 题目描述&#xff1a; 一个机器人位于一个 m x n 网…

泰山众筹模式:新零售市场的创新引领与共赢之路

在数字经济的浪潮下&#xff0c;传统的商业模式正面临挑战&#xff0c;而泰山众筹模式凭借其新颖的理念和独特的操作方式&#xff0c;正逐渐成为新零售市场的一股新势力。它不仅改变了消费者的购物体验&#xff0c;还为企业带来了新的发展机遇。 首先&#xff0c;泰山众筹模式将…

【Java】JDK1.8 HashMap源码,put源码详细讲解

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 在Java中&#xff0c;HashMap结构是被经常使用的&#xff0c;在面试当中也是经常会被问到的。这篇文章我给大家分享一下我对于HashMap结构源码的理解。 HashMap的存储与一般的数组不同&#xff0c;HashMap的每一个元素存…

Springboot集成RabbitMq+延时队列

1. 引入jar包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> 2.配置yml 2.1 配置生产者yml spring:rabbitmq:host: localhostport: 5672virtual-host: …

C语言.指针(5)

指针&#xff08;5&#xff09; 1.sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 2.数组和指针笔试题解析2.1一维数组2.2字符数组2.3二维数组 3.指针运算笔试题解析3.1 题目13.2 题目23.3 题目33.4 题目43.5 题目53.6 题目63.7 题目7 1.sizeof和strlen的对比…

SNRO 编号范围对象管控,唯一ID

事务代码:SNRO 代码引用: DATA: MAXTID TYPE I,NEWNO TYPE CHAR8. CALL FUNCTION NUMBER_RANGE_ENQUEUE EXPORTING OBJECT ZQC57 EXCEPTIONS FOREIGN_LOCK 1 OBJECT_NOT_FOUND 2 SYSTEM_FAILURE 3 OTHERS …

【论文阅读——Profit Allocation for Federated Learning】

1.摘要 由于更为严格的数据管理法规&#xff0c;如《通用数据保护条例》&#xff08;GDPR&#xff09;&#xff0c;传统的机器学习服务生产模式正在转向联邦学习这一范式。联邦学习允许多个数据提供者在其本地保留数据的同时&#xff0c;协作训练一个共享模型。推动联邦学习实…

开发日志2024-04-12

开发日志2024/04/12 1、分店月业绩和年业绩都需要添加为真实数据 **开发思路&#xff1a;**分店下所属的技师的业绩总和 代码实现&#xff1a; 前端 无 后端 //TODO 将技师多对应的积分累加到他所属的分店的月/年累计业绩销量中//TODO 查询技师所对应的分店地址String f…

智算时代的基础设施如何实现可继承可演进?浪潮云海发布 InCloud OS V8 新一代架构平台

从 2023 年开始持续火爆的 AIGC 正在加速落地应用&#xff0c;为全行业带来生产生活效率的变革与升级。面对数字化转型与智能化转型&#xff0c;对于技术团队来说&#xff0c;既要根据业务与 AI 应用去部署以云为基础的 AI 算力&#xff0c;又要与已有数据和系统&#xff08;甚…

网络流量分析与控制

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计5477字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

架构设计参考项目系列主题:新零售SaaS架构:客户管理系统架构设计

什么是客户管理系统? 客户管理系统,也称为CRM(Customer Relationship Management),主要目标是建立、发展和维护好客户关系。 CRM系统围绕客户全生命周期的管理,吸引和留存客户,实现缩短销售周期、降低销售成本、增加销售收入的目的,从而提高企业的盈利能力和竞争力。 …

YOLOV5 分类:利用yolov5进行图像分类

1、前言 之前介绍了yolov5的目标检测示例,这次将介绍yolov5的分类展示 目标检测:YOLOv5 项目:训练代码和参数详细介绍(train)_yolov5训练代码的详解-CSDN博客 yolov5和其他网络的性能对比 yolov5分类的代码部分在这 2、数据集准备 yolov5分类的数据集就是常规的摆放方式…

PyCharm远程链接AutoDL

AutoDL使用方法&#xff1a; Step1&#xff1a;确认您安装的PyCharm是社区版还是专业版&#xff0c;只有专业版才支持远程开发功能。 Step2&#xff1a;开机实例 复制自己实例的SSH指令&#xff0c;比如&#xff1a;ssh -p 38076 rootregion-1.autodl.com 在ssh -p 38076 roo…

AWS CloudFront + Route53 + EC2 + Certificate Manager

CloudFront Route53 EC2 Certificate Manager 教程 先理解它是怎么运转的 用户请求Route53解析到CloudFront&#xff0c;CloudFront解析EC2也就是资源。 了解了运作&#xff0c;接下来就一步步实现 首先处理CloudFront解析资源EC2 EC2是服务器&#xff0c;并不是资源&…

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

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

uni-app调用苹果登录,并获取用户信息

效果 模块配置 dev中的配置 需要开启登录的权限&#xff0c;然后重新下载配置文件&#xff0c;发布打包基座&#xff0c;再运行程序 代码 <button click"appleLogin">苹果登录</button>function appleLogin() {uni.login({provider: apple,success: …

预印本仓库ArXiv——防止论文录用前被别人剽窃

文章目录 一、什么是预印本二、什么是ArXiv2.1 ArXiv的领域2.2 如何使用 一、什么是预印本 预印本&#xff08;Preprint&#xff09;是指科研工作者的研究成果还未在正式出版物上发表&#xff0c;而出于和同行交流目的自愿先在学术会议上或通过互联网发布的科研论文、科技报告…

使用了代理IP怎么还会被封?代理IP到底有没有效果?

代理IP作为一种网络工具&#xff0c;被广泛应用于各种场景&#xff0c;例如网络爬虫、海外购物、规避地区限制等。然而&#xff0c;很多用户在使用代理IP的过程中却发现自己的账号被封禁&#xff0c;这让他们不禁产生疑问&#xff1a;使用了代理IP怎么还会被封&#xff1f;代理…