为什么要用ApplicationContextAware?为什么不直接用@Autowired?

为什么要用ApplicationContextAware?为什么不直接用@Autowired?

ApplicationContextAware 接口和 @Autowired 注解在 Spring 框架中都用于依赖注入,但它们的应用场景略有不同。

ApplicationContextAware 接口

  • 当一个类实现了 ApplicationContextAware 接口时,Spring 容器会自动调用其 setApplicationContext 方法,并将当前的 ApplicationContext 对象作为参数传入。
  • 这使得类能够获取到 Spring 容器的上下文信息,可以在需要时直接通过 ApplicationContext 访问 Spring 容器中的各种 Bean 和其它容器特性。
  • 主要用途是在需要获取 Spring 容器本身的信息时,比如动态获取 Bean、获取容器的环境信息等。

@Autowired 注解

  • @Autowired 是 Spring 提供的依赖注入方式之一,它可以用来自动装配 Spring 容器中的 Bean。
  • 可以用在字段、构造方法、Setter 方法上,Spring 会自动在需要的时候注入相应的 Bean 实例。
  • 主要用途是在类内部需要依赖其它 Bean 时进行注入,简化了手动获取 Bean 的过程。

选择使用 ApplicationContextAware 还是 @Autowired 主要取决于具体的需求:

  • 如果需要在类中获取 Spring 容器本身的信息,或者需要动态获取 Bean,可以考虑实现 ApplicationContextAware 接口。
  • 如果只是简单地注入其它 Bean,可以直接使用 @Autowired 注解来完成依赖注入,代码更加简洁和直观。

————————–

在一些开源的Spring工具库中会看到这种技术的使用,因为这些库往往需要与Spring容器交互,比如读取容器的配置,访问其他的bean等等,通过实现ApplicationContextAware接口就可以非常方便地完成这些工作。

但注意,一般不推荐在的业务代码中使用,因为这样会增加代码与Spring的耦合性,违反了“依赖于抽象,而非依赖于具体实现”的面向对象设计原则。业务代码应当尽可能减少对具体框架的依赖,以提高代码的通用性和可移植性。

https://baijiahao.baidu.com/s?id=1792933358078512908&wfr=spider&for=pc

获取 Spring 容器本身的信息是指什么信息

获取 Spring 容器本身的信息指的是能够在运行时获取到 Spring 容器的各种特性和管理的对象,例如:

  1. 获取 Bean 对象:通过 ApplicationContext 可以获取到 Spring 容器管理的各个 Bean 对象,包括单例 Bean、原型 Bean 等,可以根据 Bean 的名称或类型动态获取。
  2. 获取环境信息:可以获取到 Spring 容器当前运行的环境信息,如配置文件中定义的属性值、运行时环境变量等。
  3. 获取资源文件:可以加载 Spring 容器管理的资源文件,如配置文件、国际化资源等。
  4. 获取应用上下文的元数据:可以获取到 Spring 容器的元数据信息,如 Bean 的定义信息、注入的属性值、AOP 的代理信息等。
  5. 动态注册 Bean:可以通过编码的方式动态向 Spring 容器中注册 Bean,而不需要依赖静态的 XML 配置或者注解扫描。
  6. 监听容器事件:可以注册监听器来监听 Spring 容器的事件,如容器初始化完成、Bean 加载完成等事件,从而进行相应的处理。

这些功能使得 ApplicationContextAware 接口能够让类在需要时通过 ApplicationContext 访问 Spring 容器的各种管理和配置信息,从而更加灵活地进行开发和集成。

为什么当一个类实现了 ApplicationContextAware 接口时,Spring 容器会自动调用其 setApplicationContext 方法

当一个类实现了 ApplicationContextAware 接口时,Spring 容器会自动调用其 setApplicationContext 方法,主要是因为 Spring 容器在实例化 Bean 的过程中会检测到该类实现了 ApplicationContextAware 接口,从而执行以下步骤:

  1. 检测接口实现:在实例化 Bean 的过程中,Spring 容器会检测该 Bean 是否实现了 ApplicationContextAware 接口。
  2. 类型匹配:如果发现该 Bean 类型实现了 ApplicationContextAware 接口,容器就会预期该 Bean 具有 setApplicationContext 方法,这是由接口定义决定的。
  3. 自动注入:Spring 容器在完成 Bean 的实例化和依赖注入后,会自动调用 setApplicationContext 方法,并将当前的 ApplicationContext 实例作为参数传入。
  4. 初始化完成:通过调用 setApplicationContext 方法,该 Bean 可以在初始化阶段获取到 Spring 容器的 ApplicationContext 对象,从而可以在需要时访问 Spring 容器管理的其他 Bean、获取环境信息等。

实现了 ApplicationContextAware 接口的类之所以会自动调用 setApplicationContext 方法,主要是因为它表明了该类希望通过实现 Aware 接口来获取特定的 Spring 容器资源或信息。

在 Spring 框架中,有一系列的 Aware 接口,如 ApplicationContextAwareBeanNameAwareBeanFactoryAware 等。这些接口都是一种约定,用来告知 Spring 框架某个类希望在实例化后,通过特定方法接收相关的容器资源或信息。

具体来说:

  • Aware 接口:是一组接口,如 ApplicationContextAware,它们是 Spring 框架定义的一种标准接口。实现这些接口的类,通常需要在特定的方法中接收相关的容器资源或信息。
  • 自动调用:Spring 容器在实例化 Bean 后,会检测并处理实现了 Aware 接口的类。当发现某个 Bean 实现了某个 Aware 接口时(如 ApplicationContextAware),容器就会自动调用对应的接口方法(如 setApplicationContext),并将相应的容器资源作为参数传入。

在 Java 和 Spring 框架中,有时会出现像 Aware 这样的接口,其代码内容看起来是空的。这种情况通常发生在以下几种情况下:

  1. 接口仅作为标记接口存在
    • 标记接口是一种没有任何方法声明的接口,仅用于标识类是否具有某种特定的语义或功能需求。例如,java.io.Serializable 就是一个标记接口,用来表示类可以被序列化。
    • 在 Spring 中,像 Aware 接口可能仅作为一个标记接口存在,用来表明实现了该接口的类具有某种感知(Aware)的能力,而具体的感知操作实现在子接口中或者在实现类中的特定方法中。

在 Spring 框架中,对于标记接口(如 Aware 接口)的检测是通过反射和约定来完成的。具体来说,Spring 框架在处理 Bean 的初始化和依赖注入时会进行如下操作:

  1. Bean 实例化和初始化:当 Spring 容器加载配置文件并创建 Bean 的实例时,会检查每个 Bean 的类型信息。
  2. 接口实现检测:如果某个 Bean 的类型实现了 Aware 接口(例如 ApplicationContextAware),Spring 容器会识别到这个标记并进行相应处理。
  3. 调用特定方法:Spring 容器在实例化完成后,会检查实现了 Aware 接口的 Bean,并调用相应的约定方法(例如 setApplicationContext 方法),将相关的容器资源传递给该方法。
  4. 基于约定的设计:Spring 框架的设计基于约定优于配置的原则,这意味着框架通过约定的方式来实现各种功能,如依赖注入、生命周期管理等。因此,对于标记接口的使用和检测是在框架内部通过一系列的约定和反射机制实现的。

具体到你的问题,虽然 Aware 接口的定义本身是空的,但是 Spring 框架会在处理 Bean 的过程中通过反射和特定的逻辑,检测到实现了 Aware 接口的 Bean,并自动调用其约定的方法,以实现相应的功能扩展或配置。

todo: 约定写在了哪里?具体代码在哪里

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注