你好,这里是codetrend专栏“Spring6全攻略”。
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
Aware接口的设计是为了让Bean能够感知到其所处的环境并与之交互。通过实现这些接口,Bean可以获取对Spring容器或其他相关资源的引用,从而能够更好地适应和利用所处的环境。
名称 | 注入的依赖 |
---|---|
ApplicationContextAware(常用) | 声明的 ApplicationContext。 |
ApplicationEventPublisherAware | 包含的 ApplicationContext 的事件发布器。 |
BeanClassLoaderAware | 用于加载 bean 类的类加载器。 |
BeanFactoryAware(常用) | 声明的 BeanFactory。 |
BeanNameAware | 声明 bean 的名称。 |
LoadTimeWeaverAware | 在加载时处理类定义的已定义织入器。 |
MessageSourceAware | 配置用于解析消息的策略(支持参数化和国际化)。 |
NotificationPublisherAware | Spring JMX 通知发布器。 |
ResourceLoaderAware | 配置的加载器,用于低级别访问资源。 |
ServletConfigAware | 容器运行的当前 ServletConfig。仅在 web 感知的 Spring ApplicationContext 中有效。 |
ServletContextAware | 容器运行的当前 ServletContext。仅在 web 感知的 Spring ApplicationContext 中有效。 |
实现这个接口的Bean可以在其初始化时获取到ApplicationContext,从而能够访问Spring容器中的所有Bean及其配置。具体来说,这个接口主要用于需要与Spring上下文进行交互的场景。
例子代码如下:
class ContextAwareBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void showBeanDetails() {
String[] beanNames = applicationContext.getBeanDefinitionNames();
System.out.println("Bean names in ApplicationContext:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
注意事项:
ApplicationEventPublisherAware接口允许Bean获取到ApplicationEventPublisher实例,以便能够发布事件。通过实现该接口,Bean可以在运行时向应用程序上下文发布自定义事件或标准Spring事件。
例子代码如下:
@Getter
class CustomEvent extends ApplicationEvent {
private final String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
}
/**
* 事件发布
*/
@Component
class EventPublisherBean implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void publishCustomEvent(final String message) {
CustomEvent customEvent = new CustomEvent(this, message);
applicationEventPublisher.publishEvent(customEvent);
}
}
/**
* 事件监听
*/
@Component
class CustomEventListener {
@EventListener
public void handleCustomEvent(CustomEvent event) {
System.out.println("Received custom event - " + event.getMessage());
}
}
测试代码输出如下:
Received custom event - Hello, Spring Events!
注意事项:
通过实现这个接口,Bean可以在其生命周期内访问加载它的类加载器,从而进行一些需要类加载器操作的任务。
实现demo如下:
/**
* 说明:BeanClassLoaderAware demo
* @since 2024/6/13
* @author sunz
*/
public class ClassLoaderAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppScanConfig.class);
ClassLoaderAwareBean classLoaderAwareBean = context.getBean(ClassLoaderAwareBean.class);
classLoaderAwareBean.performClassLoadingTask("org.springframework.beans.factory.BeanClassLoaderAware");
// 销毁容器
context.close();
}
}
@Component
class ClassLoaderAwareBean implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
System.out.println("ClassLoader has been set.");
}
public void performClassLoadingTask(String clsName) {
try {
// 例如动态加载一个类
Class<?> loadedClass = classLoader.loadClass(clsName);
System.out.println("Class loaded: " + loadedClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出结果如下:
ClassLoader has been set.
Class loaded: org.springframework.beans.factory.BeanClassLoaderAware
注意事项:
通过实现这个接口,Bean 可以在自身的生命周期中访问 Spring 容器,从而动态地获取其他 Bean 或者进行一些容器级别的操作。
比如写个策略模式,通过策略动态获取bean就可能用到。
一般场景如下:
Demo代码如下:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
/**
* 说明:BeanFactoryAware 例子
* @since 2024/6/13
* @author sunz
*/
public class BeanFactoryAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppScanConfig.class);
MyBeanFactoryAware bean = context.getBean(MyBeanFactoryAware.class);
bean.doSomething();
// 销毁容器
context.close();
}
}
@Component
class MyBeanFactoryAware implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void doSomething() {
// 现在可以使用 beanFactory 来获取其他的 Bean
MyService myService = beanFactory.getBean(MyService.class);
myService.performAction();
}
}
@Component
class MyService {
public void performAction() {
System.out.println("hello world");
}
}
注意事项:
实现这个接口的 Bean 对象在被 Spring 容器实例化后,能够获取到自己在容器中的名称。
这在某些情况下可能会非常有用,例如在调试、日志记录或需要根据 Bean 名称执行特定逻辑时。
一般应用场景:
demo代码如下:
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
/**
* 说明: BeanNameAware 例子
*
* @author sunz
* @since 2024/6/13
*/
public class BeanNameAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppScanConfig.class);
MyBeanNameAware bean = context.getBean(MyBeanNameAware.class);
bean.setBeanName("hello,jack");
bean.printBeanName();
// 销毁容器
context.close();
}
}
@Component
class MyBeanNameAware implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
public void printBeanName() {
System.out.println("Bean name is: " + beanName);
}
}
注意事项:
实现这个接口的 Bean 在被 Spring 容器实例化后,能够获取到一个 LoadTimeWeaver
实例。LoadTimeWeaver 是用于在类加载时进行字节码增强的重要机制之一,比如在 AOP(面向切面编程)中动态地织入横切关注点。
代码没什么实际使用场景,开源项目搜索也没发现使用例子,实际使用还是比较少。
不推荐使用,使用AOP还是直接用spring aop即可。
实际使用代码和之前的Aware是一致的,只要实现接口即可。
class MyLoadTimeWeaverAware implements LoadTimeWeaverAware {
private LoadTimeWeaver loadTimeWeaver;
@Override
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
this.loadTimeWeaver = loadTimeWeaver;
}
public void doSomething() {
// 使用 loadTimeWeaver 进行字节码增强等操作
// 这里仅作为示例,不进行实际操作
System.out.println("LoadTimeWeaver is set and can be used now.");
}
}
MessageSourceAware 是 Spring 框架中的一个接口,用于实现国际化(i18n)的功能。它允许一个 bean 接收 MessageSource 对象,从而能够在应用程序中访问国际化的消息资源。
实现 MessageSourceAware 接口的类可以直接使用 MessageSource 来获取国际化的消息,而不必显式地在其配置中注入 MessageSource bean。
这对于需要频繁访问国际化消息的 bean 非常有用。
例子代码如下:
/**
* 说明:MessageSourceAware demo
* @since 2024/6/13
* @author sunz
*/
public class MessageSourceAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppMessageConfig.class);
GreetingService bean = context.getBean(GreetingService.class);
String greetingEn = bean.getGreeting("John", Locale.ENGLISH);
System.out.println(greetingEn); // 输出: Hello, John!
String greetingZh = bean.getGreeting("李雷", Locale.CHINESE);
System.out.println(greetingZh); // 输出: 你好, 李雷!
// 销毁容器
context.close();
}
}
/**
* 配置类
*/
@Configuration
@ComponentScan(basePackages = "io.yulin.learn.spring.s108")
class AppMessageConfig {
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
/**
* 服务bean
*/
@Component
class GreetingService implements MessageSourceAware {
private MessageSource messageSource;
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public String getGreeting(String name, Locale locale) {
return messageSource.getMessage("greeting", new Object[]{name}, locale);
}
}
其中资源文件如下:
<!-- messages_en.properties -->
greeting=Hello, {0}!
<!-- messages_zh.properties -->
greeting=你好, {0}!
一般情况下使用多语言工具可以进行二次封装,使得使用起来更简洁方便,而不是每次进行注入。
以下是一个封装的例子:
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Locale;
@Component
public class MessageUtils {
private static MessageSource messageSource;
// Spring 会自动注入该方法中的参数 messageSource
public MessageUtils(MessageSource messageSource) {
MessageUtils.messageSource = messageSource;
}
/**
* 获取国际化消息
*
* @param code 消息代码
* @param args 消息参数
* @return 国际化消息
*/
public static String getMessage(String code, Object... args) {
Locale locale = LocaleContextHolder.getLocale();
return messageSource.getMessage(code, args, locale);
}
}
NotificationPublisherAware 是 Spring 框架中的一个接口,用于与 JMX(Java Management Extensions)相关的通知机制进行集成。实现该接口的 bean 可以通过 Spring 容器获得一个 NotificationPublisher 实例,从而能够发布 JMX 通知。
在需要发布 JMX 通知的 Spring 管理的 bean 中,实现 NotificationPublisherAware 接口可以方便地获取 NotificationPublisher 并发布通知。这通常用于监控和管理应用程序状态变化,如资源使用情况、性能指标等。
例子代码如下:
/**
* 说明:NotificationPublisherAware demo
* @since 2024/6/13
* @author sunz
*/
public class NotificationPublisherAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppNotifyConfig.class);
MyManagedBean bean = context.getBean(MyManagedBean.class);
bean.doSomething();
// 销毁容器
context.close();
}
}
@Configuration
@ComponentScan(basePackages = "io.yulin.learn.spring.s108")
class AppNotifyConfig{
@Bean
public MBeanExporter mBeanExporter() {
MBeanExporter exporter = new MBeanExporter();
exporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING);
Map<String, Object> beans = new HashMap<>();
beans.put("bean:name=myManagedBean", myManagedBean());
exporter.setBeans(beans);
return exporter;
}
@Bean
public MyManagedBean myManagedBean() {
return new MyManagedBean();
}
}
/**
* 服务bean
*/
@Component
class MyManagedBean extends NotificationBroadcasterSupport implements MyManagedBeanMBean,NotificationPublisherAware {
private NotificationPublisher notificationPublisher;
@Override
public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
this.notificationPublisher = notificationPublisher;
}
@Override
public void doSomething() {
// 执行某些操作
System.out.println("Doing something...");
// 发布通知
Notification notification = new Notification(
"myNotificationType",
this,
System.currentTimeMillis(),
"Something happened!"
);
if (this.notificationPublisher != null) {
notificationPublisher.sendNotification(notification);
} else {
// 使用 NotificationBroadcasterSupport 自带的方法
sendNotification(notification);
}
}
}
JMX接收和监听比较复杂,这里只是使用了NotificationPublisher进行推送通知消息。
实现 ResourceLoaderAware 接口的类会在其被 Spring 容器管理时自动获得一个 ResourceLoader 实例。通过这个实例,类可以方便地加载各种类型的资源(如文件系统、类路径、URL 等)。
通常在需要访问外部资源(例如文件、配置文件、图片等)的类中,可以实现 ResourceLoaderAware 接口。这比直接依赖 File 或其他资源加载机制更灵活,因为 ResourceLoader 可以处理多种类型的资源路径(如类路径、文件系统路径、URL 等)。
以下是一个简单的示例,展示了如何实现 ResourceLoaderAware 并使用 ResourceLoader 加载文本文件。
/**
* 说明:ResourceLoaderAware demo
* @since 2024/6/14
* @author sunz
*/
public class ResourceLoaderAwareDemo {
public static void main(String[] args) {
// 创建一个基于 Java Config 的应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppScanConfig.class);
MyResourceLoaderAwareBean bean = context.getBean(MyResourceLoaderAwareBean.class);
// 假设 "test.txt" 位于 classpath 路径下
bean.loadResource("classpath:application.yml");
// 销毁容器
context.close();
}
}
/**
* 服务bean
*/
@Component
class MyResourceLoaderAwareBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void loadResource(String location) {
try {
Resource resource = resourceLoader.getResource(location);
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
实现 ServletConfigAware 接口的类会在其被 Spring 容器管理时自动获得一个 ServletConfig 实例。通过这个实例,类可以方便地获取关于当前 Servlet 的配置信息。
使用demo如下:
/**
* 服务bean
*/
@RestController
@RequestMapping("/test")
public class MyServletConfigAwareBean implements ServletConfigAware {
private ServletConfig servletConfig;
@Override
public void setServletConfig(ServletConfig servletConfig) {
this.servletConfig = servletConfig;
}
@GetMapping("/demo")
public void printServletInfo() {
String servletName = servletConfig.getServletName();
String initParamValue = servletConfig.getInitParameter("myInitParam");
String contextPath = servletConfig.getServletContext().getContextPath();
System.out.println("Servlet Name: " + servletName);
System.out.println("Init Param Value: " + initParamValue);
System.out.println("Context Path: " + contextPath);
}
}
实际验证会发现servletConfig
报空指针异常,这块是因为没初始化相关的配置导致的。
ServletContextAware 接口是 Spring 框架中的一个接口,用于让实现它的类获取当前 Servlet 上下文(ServletContext)的引用。通过实现这个接口,类可以在 Spring 容器初始化时自动获取 Servlet 上下文对象,从而进行一些与 Servlet 相关的操作。
使用demo如下:
@RestController
@RequestMapping("/test2")
public class MyServletContextAwareBean implements ServletContextAware {
private ServletContext servletContext;
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
// 可以添加其他方法来使用 servletContext 对象
@GetMapping("/demo")
public void printServletInfo() {
System.out.println("ServletContext: " + servletContext);
System.out.println("ServletContext name: " + servletContext.getServletContextName());
System.out.println("ServletContext context path: " + servletContext.getContextPath());
System.out.println("ServletContext server info: " + servletContext.getServerInfo());
System.out.println("ServletContext major version: " + servletContext.getMajorVersion());
System.out.println("ServletContext minor version: " + servletContext.getMinorVersion());
}
}
ServletContext 常用的场景如下:
点击话题和专栏可以看更多往期文章。
来自一线全栈程序员nine的探索与实践,持续迭代中。
欢迎关注、评论、点赞。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有