首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

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

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

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

核心概念

它能解决什么问题?

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

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

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

依赖注入:Spring的核心功能之一就是依赖注入(DI),但有时候标准的依赖注入方式可能无法满足某些特定的需求。例如,当需要访问当前Bean的名称、BeanFactory或ApplicationContext等信息,通过实现相应的Aware接口,可以让Spring容器在初始化Bean时自动将这些信息注入到Bean中。

环境感知:有时候,Bean的行为可能需要根据其所处的环境进行调整,例如,在不同的ApplicationContext中,Bean可能需要进行不同的配置或初始化操作,通过实现ApplicationContextAware接口,Bean可以访问到当前的ApplicationContext,并据此进行环境感知的操作。

资源访问:除了基本的依赖注入和环境感知外,Aware接口还可以用于访问Spring容器中的其他资源。例如,通过实现ResourceLoaderAware接口,Bean可以获得一个ResourceLoader的引用,用于加载类路径下的资源文件。

它有哪些子类拓展?

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

BeanNameAware: 实现此接口的bean可以获得其在Spring容器中的名称,当bean被创建并添加到容器中时,Spring会调用setBeanName(String name)方法。

BeanFactoryAware: 实现此接口的bean可以获得对其所在的BeanFactory的引用,这允许bean直接访问容器以查找或操作其他bean,通过setBeanFactory(BeanFactory beanFactory)方法注入。

ApplicationContextAware: 与BeanFactoryAware类似,但是提供对更高级的ApplicationContext的访问,实现此接口的bean可以通过setApplicationContext(ApplicationContext context)方法获得ApplicationContext的引用。

MessageSourceAware: 实现此接口的bean可以获得对MessageSource的引用,这允许bean进行国际化消息的处理,通过setMessageSource(MessageSource messageSource)方法注入。

ApplicationEventPublisherAware: 实现此接口的bean可以获得一个ApplicationEventPublisher的引用,用于发布应用事件,Spring会在适当时刻调用setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)方法。

ResourceLoaderAware: 实现此接口的bean可以获得对ResourceLoader的引用,这使得bean可以加载资源,如配置文件等,通过setResourceLoader(ResourceLoader resourceLoader)方法注入。

EnvironmentAware: 实现此接口的bean可以获得对当前应用环境的Environment对象的引用。这允许bean查询配置的属性、配置文件等,通过setEnvironment(Environment environment)方法注入。

EmbeddedValueResolverAware: 实现此接口的bean可以获得对字符串值解析器的引用,该解析器能够处理占位符(如${...}),通过setEmbeddedValueResolver(StringValueResolver resolver)方法注入。

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来获取它:

接下来,创建一个配置类来启动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来获取它:

接下来,创建一个配置类来启动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,类中通过@Autowired将MyResourceLoaderAwareComponent注入进来,如下:

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容器中的其他资源的引用。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/O-2xBcJoHhpU8aphhwbec1xw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券