Spring揭秘:Aware接口应用场景及实现原理!

简介: Aware接口赋予了Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContext、BeanFactory等。这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性,从而让Spring的IoC容器变得更加强大和灵活。

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

内容概要

Aware接口赋予了Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContextBeanFactory等。

这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性,从而让Spring的IoC容器变得更加强大和灵活。

核心概念

它能解决什么问题?

在Spring中,Aware接口是一种标记接口,它本身并没有定义任何方法,但是Spring提供了一系列以Aware命名的接口,如BeanNameAwareBeanFactoryAwareApplicationContextAware等。

这些接口定义了一些回调方法,通过这些回调方法,Spring容器在初始化Bean时会将容器中的一些资源、状态、环境信息注入到Bean中,使Bean能够感知到这些信息并据此进行相应的操作。

Aware接口主要用来解决以下技术问题:

  1. 依赖注入:Spring的核心功能之一就是依赖注入(DI),但有时候标准的依赖注入方式可能无法满足某些特定的需求。例如,当需要访问当前Bean的名称、BeanFactory或ApplicationContext等信息,通过实现相应的Aware接口,可以让Spring容器在初始化Bean时自动将这些信息注入到Bean中。
  2. 环境感知:有时候,Bean的行为可能需要根据其所处的环境进行调整,例如,在不同的ApplicationContext中,Bean可能需要进行不同的配置或初始化操作,通过实现ApplicationContextAware接口,Bean可以访问到当前的ApplicationContext,并据此进行环境感知的操作。
  3. 资源访问:除了基本的依赖注入和环境感知外,Aware接口还可以用于访问Spring容器中的其他资源。例如,通过实现ResourceLoaderAware接口,Bean可以获得一个ResourceLoader的引用,用于加载类路径下的资源文件。

它有哪些子类拓展?

以下是Aware接口的一些常见的子类实现,如下:

  1. BeanNameAware: 实现此接口的bean可以获得其在Spring容器中的名称,当bean被创建并添加到容器中时,Spring会调用setBeanName(String name)方法。
  2. BeanFactoryAware: 实现此接口的bean可以获得对其所在的BeanFactory的引用,这允许bean直接访问容器以查找或操作其他bean,通过setBeanFactory(BeanFactory beanFactory)方法注入。
  3. ApplicationContextAware: 与BeanFactoryAware类似,但是提供对更高级的ApplicationContext的访问,实现此接口的bean可以通过setApplicationContext(ApplicationContext context)方法获得ApplicationContext的引用。
  4. MessageSourceAware: 实现此接口的bean可以获得对MessageSource的引用,这允许bean进行国际化消息的处理,通过setMessageSource(MessageSource messageSource)方法注入。
  5. ApplicationEventPublisherAware: 实现此接口的bean可以获得一个ApplicationEventPublisher的引用,用于发布应用事件,Spring会在适当时刻调用setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)方法。
  6. ResourceLoaderAware: 实现此接口的bean可以获得对ResourceLoader的引用,这使得bean可以加载资源,如配置文件等,通过setResourceLoader(ResourceLoader resourceLoader)方法注入。
  7. EnvironmentAware: 实现此接口的bean可以获得对当前应用环境的Environment对象的引用。这允许bean查询配置的属性、配置文件等,通过setEnvironment(Environment environment)方法注入。
  8. EmbeddedValueResolverAware: 实现此接口的bean可以获得对字符串值解析器的引用,该解析器能够处理占位符(如${...}),通过setEmbeddedValueResolver(StringValueResolver resolver)方法注入。
  9. SchedulingConfigurerAware (不直接属于Aware接口系列, 但类似): 允许配置计划任务,在Spring Boot应用中,可以通过实现SchedulingConfigurer接口和覆盖configureTasks(ScheduledTaskRegistrar taskRegistrar)方法来定义计划任务。

代码案例

下面列举举个常见的Aware子类实现案例。

BeanFactoryAware接口

BeanFactoryAware接口允许一个bean在初始化时获得对BeanFactory的引用,这通常用于需要以编程方式访问其他bean或执行与容器相关的操作的场景。下面是一个简单的例子,演示了BeanFactoryAware接口使用,如下代码:

先创建一个实现了BeanFactoryAware接口的类:

import org.springframework.beans.BeansException;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.BeanFactoryAware;  
import org.springframework.stereotype.Component;  

@Component  
public class MyBeanFactoryAwareBean implements BeanFactoryAware {
   
     

    private BeanFactory beanFactory;  

    // 实现BeanFactoryAware接口的回调方法  
    @Override  
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
   
     
        this.beanFactory = beanFactory;  
    }  

    // 一个简单的方法,用于从BeanFactory中获取bean  
    public Object getBean(String beanName) {
   
     
        return beanFactory.getBean(beanName);  
    }  
}

然后,创建一个简单的bean,后面将通过MyBeanFactoryAwareBean来获取它:

import org.springframework.stereotype.Component;  

@Component  
public class MySimpleBean {
   
     
    public String sayHello() {
   
     
        return "Hello from MySimpleBean!";  
    }  
}

接下来,创建一个配置类来启动Spring应用:

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

@Configuration  
@ComponentScan(basePackages = "com.example") // 假设上面的类在com.example包下  
public class AppConfig {
   
     
    // 这里不需要额外的bean定义,因为@Component注解已经足够  
}

最后,编写一个客户端类来运行应用并测试MyBeanFactoryAwareBean

import org.springframework.context.ApplicationContext;  
import org.springframework.context.annotation.AnnotationConfigApplicationContext;  

public class ClientApp {
   
     

    public static void main(String[] args) {
   
     
        // 创建一个Spring应用上下文  
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  

        // 获取MyBeanFactoryAwareBean的实例  
        MyBeanFactoryAwareBean beanFactoryAwareBean = context.getBean(MyBeanFactoryAwareBean.class);  

        // 使用MyBeanFactoryAwareBean来获取MySimpleBean的实例  
        MySimpleBean simpleBean = (MySimpleBean) beanFactoryAwareBean.getBean("mySimpleBean");  

        // 调用MySimpleBean的方法并打印结果  
        System.out.println(simpleBean.sayHello());  

        // 关闭应用上下文  
        ((AnnotationConfigApplicationContext) context).close();  
    }  
}

ApplicationContextAware接口

ApplicationContextAware接口允许一个bean在初始化时获得对ApplicationContext的引用,通常用于需要以编程方式访问其他bean或执行与Spring应用上下文相关的操作的场景。

如下代码,演示了如何实现ApplicationContextAware接口,并在客户端代码中调用该bean。

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

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

@Component  
public class MyApplicationContextAwareBean implements ApplicationContextAware {
   
     

    private ApplicationContext applicationContext;  

    // 实现ApplicationContextAware接口的回调方法  
    @Override  
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
   
     
        this.applicationContext = applicationContext;  
    }  

    // 一个简单的方法,用于从ApplicationContext中获取bean  
    public Object getBean(String beanName) {
   
     
        return applicationContext.getBean(beanName);  
    }  
}

然后,创建一个简单的bean,稍后将通过MyApplicationContextAwareBean来获取它:

import org.springframework.stereotype.Component;  

@Component  
public class MySimpleBean {
   
     
    public String sayHello() {
   
     
        return "Hello from MySimpleBean!";  
    }  
}

接下来,创建一个配置类来启动Spring应用:

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

@Configuration  
@ComponentScan(basePackages = "com.example") // 假设上面的类在com.example包下  
public class AppConfig {
   
     
    // 这里不需要额外的bean定义,因为@Component注解已经足够  
}

最后,编写一个客户端类来运行应用并测试MyApplicationContextAwareBean

import org.springframework.context.ApplicationContext;  
import org.springframework.context.annotation.AnnotationConfigApplicationContext;  

public class ClientApp {
   
     

    public static void main(String[] args) {
   
     
        // 创建一个Spring应用上下文  
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  

        // 获取MyApplicationContextAwareBean的实例  
        MyApplicationContextAwareBean contextAwareBean = context.getBean(MyApplicationContextAwareBean.class);  

        // 使用MyApplicationContextAwareBean来获取MySimpleBean的实例  
        MySimpleBean simpleBean = (MySimpleBean) contextAwareBean.getBean("mySimpleBean");  

        // 调用MySimpleBean的方法并打印结果  
        System.out.println(simpleBean.sayHello());  

        // 关闭应用上下文(尽管在这个例子中不是必须的,因为main方法结束后JVM会退出)  
        ((AnnotationConfigApplicationContext) context).close();  
    }  
}

EnvironmentAware接口

EnvironmentAware接口允许bean在其初始化之后访问到Environment属性。

Environment表示当前应用环境,它封装了应用程序环境的配置属性,例如系统属性、环境变量以及应用上下文中的属性。

如下代码,演示了如何实现Environment接口。

创建一个类MyEnvironmentAwareBean实现EnvironmentAware接口:

import org.springframework.beans.BeansException;  
import org.springframework.beans.factory.BeanNameAware;  
import org.springframework.beans.factory.config.ConfigurableBeanFactory;  
import org.springframework.beans.factory.EnvironmentAware;  
import org.springframework.context.EnvironmentAwareBean;  
import org.springframework.core.env.Environment;  

public class MyEnvironmentAwareBean implements EnvironmentAware {
   
     

    private Environment environment;  

    // 实现 EnvironmentAware 接口的 setEnvironment 方法  
    @Override  
    public void setEnvironment(Environment environment) throws BeansException {
   
     
        this.environment = environment;  
    }  

    // 一个简单的方法,用于输出某个属性的值  
    public void printProperty(String propertyName) {
   
     
        String propertyValue = environment.getProperty(propertyName);  
        System.out.println("Property '" + propertyName + "' = " + propertyValue);  
    }  
}

上面的代码中MyEnvironmentAwareBean类实现了EnvironmentAware接口,并通过setEnvironment方法接收Environment对象。

接下来,配置Spring上下文,注册MyEnvironmentAwareBean bean,并通过一个客户端类调用它:

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

@Configuration  
public class AppConfig {
   
     

    // 声明 MyEnvironmentAwareBean 为一个 bean  
    @Bean  
    public MyEnvironmentAwareBean myEnvironmentAwareBean() {
   
     
        return new MyEnvironmentAwareBean();  
    }  
}  

public class ClientApp {
   
     

    public static void main(String[] args) {
   
     
        // 创建 AnnotationConfigApplicationContext 上下文  
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  

        // 从上下文中获取 MyEnvironmentAwareBean 实例  
        MyEnvironmentAwareBean myBean = context.getBean(MyEnvironmentAwareBean.class);  

        // 调用 printProperty 方法,打印系统属性 java.version  
        myBean.printProperty("java.version");  

        // 关闭上下文  
        context.close();  
    }  
}

ResourceLoaderAware接口

如下代码,演示了如何实现Environment接口:

创建一个类MyResourceLoaderAwareComponent实现ResourceLoaderAware接口,并实现setResourceLoader方法

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.context.ResourceLoaderAware;  
import org.springframework.core.io.Resource;  
import org.springframework.core.io.ResourceLoader;  
import org.springframework.stereotype.Component;  

import java.io.IOException;  
import java.io.InputStream;  
import java.nio.charset.StandardCharsets;  
import java.util.Scanner;  

// 声明这是一个Spring组件  
@Component  
public class MyResourceLoaderAwareComponent implements ResourceLoaderAware {
   
     

    private ResourceLoader resourceLoader;  

    // 实现了ResourceLoaderAware接口的setResourceLoader方法  
    @Override  
    public void setResourceLoader(ResourceLoader resourceLoader) {
   
     
        this.resourceLoader = resourceLoader;  
    }  

    // 使用ResourceLoader加载资源并返回资源内容  
    public String loadResourceContent(String location) {
   
     
        Resource resource = resourceLoader.getResource(location);  
        try (InputStream inputStream = resource.getInputStream();  
             Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) {
   
     

            StringBuilder content = new StringBuilder();  
            while (scanner.hasNextLine()) {
   
     
                content.append(scanner.nextLine()).append("\n");  
            }  
            return content.toString();  
        } catch (IOException e) {
   
     
            throw new RuntimeException("Failed to load resource: " + location, e);  
        }  
    }  
}

创建换一个client类MyResourceLoaderAwareClient,类中通过@AutowiredMyResourceLoaderAwareComponent注入进来,如下:

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Component;  

@Component  
public class MyResourceLoaderAwareClient {
   
     

    private final MyResourceLoaderAwareComponent myResourceLoaderAwareComponent;  

    @Autowired  
    public MyResourceLoaderAwareClient(MyResourceLoaderAwareComponent myResourceLoaderAwareComponent) {
   
     
        this.myResourceLoaderAwareComponent = myResourceLoaderAwareComponent;  
    }  

    // 客户端方法,用于调用加载资源的方法并打印结果  
    public void printResourceContent(String location) {
   
     
        String content = myResourceLoaderAwareComponent.loadResourceContent(location);  
        System.out.println("Resource content from location: " + location);  
        System.out.println(content);  
    }  
}

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

最后,Aware子类比较多,这里就不一一通过代码举例了,但是只需要记住,在Spring中提供的Aware接口都是为了能够让开发者轻松地获取到Spring容器中的其他资源的引用。

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

END!
END!
END!

往期回顾

精品文章

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

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

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

Java并发基础:CopyOnWriteArraySet全面解析

Java并发基础:ConcurrentSkipListMap全面解析

相关文章
|
1月前
|
监控 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注册中心服务 构建商品
370 3
|
4月前
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
|
1月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
1月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
706 10
|
2月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
2月前
|
NoSQL Java Redis
Redis基本数据类型及Spring Data Redis应用
Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。
382 2
|
2月前
|
Java Linux 网络安全
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
321 13
|
3月前
|
SQL Java 数据库
解决Java Spring Boot应用中MyBatis-Plus查询问题的策略。
保持技能更新是侦探的重要素质。定期回顾最佳实践和新技术。比如,定期查看MyBatis-Plus的更新和社区的最佳做法,这样才能不断提升查询效率和性能。
164 1
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
3月前
|
Java 数据库 开发者
Spring Boot 框架超级详细总结及长尾关键词应用解析
本文深入讲解Spring Boot框架的核心概念、功能特性及实际应用,涵盖自动配置、独立运行、starter依赖等优势。通过Web开发、微服务架构、批处理等适用场景分析,结合在线书店实战案例,演示项目初始化、数据库设计、分层架构实现全流程。同时探讨热部署、多环境配置、缓存机制与事务管理等高级特性,助你高效掌握Spring Boot开发技巧。代码示例详尽,适合从入门到进阶的学习者。
1230 0