Spring揭秘:ApplicationContextAware应用场景及实现原理!

简介: ApplicationContextAware接口能够轻松感知并在Spring中获取应用上下文,进而访问容器中的其他Bean和资源,这增强了组件间的解耦,了代码的灵活性和可扩展性,是Spring框架中实现高级功能的关键接口之一。

Spring揭秘:ImportBeanDefinitionRegistrar应用场景及实现原理! - 程序员古德

内容概要

ApplicationContextAware接口能够轻松感知并在Spring中获取应用上下文,进而访问容器中的其他Bean和资源,这增强了组件间的解耦,了代码的灵活性和可扩展性,是Spring框架中实现高级功能的关键接口之一。

核心概念

它能用来干啥?

为了方便理解,模拟一个业务场景。假如有一个功能模块负责处理订单,在这个模块中,有一个OrderService类,它负责订单的创建、更新和查询等操作,单在处理订单的过程中,可能需要访问其他一些服务,比如用户服务来获取用户信息,或者库存服务来检查商品库存。

在这个场景中,可以使用ApplicationContextAware接口来解决,可以创建一个类,比如叫OrderServiceContextAware,让它实现ApplicationContextAware接口,当Spring容器初始化这个类时,它会自动将应用上下文注入到这个类中,一旦注入了应用上下文,OrderServiceContextAware就能够访问到容器中的其他Bean,包括用户服务和库存服务。

可以在OrderService类中使用OrderServiceContextAware来获取用户服务和库存服务的实例,而无需直接在OrderService中注入这些服务,这样OrderService类不直接依赖于其他服务的具体实现,而是通过OrderServiceContextAware来间接访问这些服务。

它有哪些特性?

ApplicationContextAware是Spring框架提供的一个特殊的回调接口,用于帮助对象(特别是普通的Java Bean)访问到Spring的应用上下文ApplicationContext

当在自己的类中实现ApplicationContextAware接口时,可以通过Spring提供的回调机制访问到Spring的应用上下文,从而获得Spring IoC容器中的bean实例、配置信息以及进行国际化操作、事件发布等操作。

ApplicationContextAware接口中定义了一个setApplicationContext方法,当类实现了该接口之后,Spring IoC容器会自动调用该方法并将当前的ApplicationContext注入到所实现的setApplicationContext方法中,这样就可以在该类中使用Spring的应用上下文了。

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

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

代码案例

下面是一个简单的代码案例,展示了如何使用ApplicationContextAware接口来创建一个能够访问Spring应用上下文的类,如下代码:

首先,创建一个实现ApplicationContextAware接口的类:

import org.springframework.beans.BeansException;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.ApplicationContextAware;  
import org.springframework.stereotype.Component;  

@Component  
public class SpringContextUtil implements ApplicationContextAware {
   
     

    // Spring应用上下文  
    private static ApplicationContext applicationContext;  

    // 当Spring容器创建该类的实例时,会自动调用此方法,注入应用上下文  
    @Override  
    public void setApplicationContext(ApplicationContext context) throws BeansException {
   
     
        SpringContextUtil.applicationContext = context;  
    }  

    // 提供一个静态方法,返回应用上下文  
    public static ApplicationContext getApplicationContext() {
   
     
        return applicationContext;  
    }  

    // 提供一个获取Bean的静态方法  
    public static <T> T getBean(Class<T> beanClass) {
   
     
        if (applicationContext != null) {
   
     
            return applicationContext.getBean(beanClass);  
        } else {
   
     
            throw new IllegalStateException("ApplicationContext is not initialized yet!");  
        }  
    }  
}

接着,定义一个简单的服务类作为Spring Bean:

import org.springframework.stereotype.Service;  

@Service  
public class DemoService {
   
     

    public String sayHello() {
   
     
        return "Hello from DemoService!";  
    }  
}

然后,可以使用Spring的Java配置或者XML配置来定义和初始化这些Bean,假设使用Java配置:

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  

@Configuration  
public class AppConfig {
   
     

    @Bean  
    public SpringContextUtil springContextUtil() {
   
     
        return new SpringContextUtil();  
    }  

    @Bean  
    public DemoService demoService() {
   
     
        return new DemoService();  
    }  
}

最后,在客户端代码中,我们可以通过SpringContextUtil类来获取DemoService的实例并调用其方法:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;  

public class ApplicationClient {
   
     

    public static void main(String[] args) {
   
     
        // 创建Spring上下文,注册Java配置类  
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  

        // 关闭Spring上下文,以便能够正常结束程序(尽管在这个示例中可能不需要)  
        context.registerShutdownHook();  

        // 通过SpringContextUtil获取DemoService实例  
        DemoService demoService = SpringContextUtil.getBean(DemoService.class);  

        // 调用DemoService的sayHello方法  
        System.out.println(demoService.sayHello());  
    }  
}

输出结果:

复制代码

Hello from DemoService!

以上代码展示了如何通过SpringContextUtil访问Spring的应用上下文,并获取其中的一个bean(DemoService)。

ApplicationClient类是客户端代码的入口点,它初始化了一个AnnotationConfigApplicationContext,通过它Spring可以创建和管理beans,随后客户端代码使用SpringContextUtil.getBean静态方法来获取DemoService的实例,并调用它的sayHello方法。

核心API

ApplicationContextAware接口是一个特殊的标记接口。

它允许实现类能够访问到ApplicationContext,即Spring的应用上下文,ApplicationContextAware中有且只有一个核心方法,如下是该方法的说明:

public interface ApplicationContextAware extends Aware {
   
     
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;  
}

setApplicationContext方法的含义如下:

  • void setApplicationContext(ApplicationContext applicationContext) throws BeansException:
    这个方法会在Spring容器初始化的时候被自动调用,Spring容器会将当前的ApplicationContext作为参数传递给该方法,实现这个接口的类可以在这个方法中保存对ApplicationContext的引用,从而能够在后续的操作中使用这个上下文。

如下是实现ApplicationContextAware接口的类的代码案例,如下:

@Component  
public class MyApplicationContextAware implements ApplicationContextAware {
   
     
    private ApplicationContext applicationContext;  

    @Override  
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
   
     
        this.applicationContext = applicationContext;  
    }  

    public ApplicationContext getApplicationContext() {
   
     
        return this.applicationContext;  
    }  
}

技术原理

ApplicationContextAware接口是Spring框架中用于让Bean感知到Spring应用上下文ApplicationContext的存在的一个标记接口。

当Spring容器创建一个实现了ApplicationContextAware接口的Bean时,它会自动调用该Bean的setApplicationContext方法,并将当前的ApplicationContext作为参数传入,这使得Bean能够访问到Spring容器的上下文,进而可以获取容器中的其他Bean、资源、配置信息等。

实现原理

  1. 标记接口: ApplicationContextAware接口本身并没有定义任何具体的业务逻辑,它只是一个标记接口,用于告诉Spring容器这个Bean需要特殊处理。
  2. 容器回调: 当Spring容器初始化一个Bean时,如果这个Bean实现了ApplicationContextAware接口,Spring容器会调用该Bean的setApplicationContext方法,并将当前的ApplicationContext对象作为参数传入。
  3. 内部状态保存: 实现ApplicationContextAware接口的Bean通常会在其内部保存这个传入的ApplicationContext引用,以便后续使用。
  4. 使用上下文: 一旦Bean保存了ApplicationContext的引用,它就可以使用这个上下文来访问容器中的其他Bean,或者获取容器的其他服务。

工作机制

  1. Bean创建: 当Spring容器根据配置信息创建一个Bean实例时,它会检查这个Bean是否实现了任何Aware接口(包括ApplicationContextAware)。
  2. Aware接口处理: 如果Bean实现了Aware接口,Spring容器会调用相应的set*方法,注入相应的依赖,对于ApplicationContextAware,容器会调用setApplicationContext方法。
  3. 依赖注入: 在调用setApplicationContext方法时,Spring容器会将当前的ApplicationContext对象注入到Bean中,这个注入过程是通过Java反射机制实现的。
  4. Bean后处理: 在Bean的所有属性被设置之后,Spring容器会调用Bean的后处理器(如果配置了的话),进行额外的初始化工作,对于实现了InitializingBean接口的Bean,还会调用其afterPropertiesSet方法。
  5. 使用ApplicationContext: 一旦Bean被初始化并注入了ApplicationContext,它就可以使用这个上下文来执行各种操作,比如获取其他Bean、访问资源、读取配置等。

核心总结

Spring揭秘:ApplicationContextAware应用场景及实现原理! - 程序员古德

ApplicationContextAware接口允许开发者在Bean中轻松获取到应用上下文ApplicationContext,这使得Bean能够灵活地访问Spring容器中的其他Bean和资源,增强了组件间的解耦和可扩展性。

但是,过度使用ApplicationContextAware可能导致代码与Spring容器紧密耦合,降低了代码的可移植性和可测试性。

关注我,每天学习互联网编程技术 - 程序员古德

END!
END!
END!

往期回顾

精品文章

Spring揭秘:@import注解应用场景及实现原理!

Java并发基础:原子类之AtomicMarkableReference全面解析!

Java并发基础:concurrent Flow API全面解析

Java并发基础:CopyOnWriteArraySet全面解析

Java并发基础:ConcurrentSkipListMap全面解析

相关文章
|
9月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1374 3
|
8月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
804 0
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1576 13
|
7月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
654 8
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
8月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1541 5
|
9月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
677 2
|
9月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
9月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
1486 10
|
10月前
|
Java Linux 网络安全
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
970 13

热门文章

最新文章