示例工程文档【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能包括控制反转IOC容器的使用面向切面编程AOP的原理与实践事务管理的方式与实现Spring MVC 的流程与控制器工作机制以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址https://gitcode.com/GitHub_Trending/sp/spring-reading点击查看免费下载本文以 spring-reading 仓库中的 spring-aware-messageSourceAware 模块为蓝本系统讲解 Spring 中MessageSourceAware接口的作用、使用场景与底层工作原理它如何让 Bean 在初始化阶段自动获得MessageSource引用从而借助属性文件实现国际化i18n消息检索。读完本文你将掌握MessageSourceAware的完整用法含配置类、Bean 实现与属性文件组织方式并沿着refresh()→initMessageSource()→finishBeanFactoryInitialization()→ApplicationContextAwareProcessor的调用链理解 Spring 容器在幕后完成 Aware 注入的源码级机制。一、MessageSourceAware是什么MessageSourceAware是 Spring 框架自1.1.1版本开始引入的一个核心回调接口作者Juergen Hoeller、Chris Beams它继承自Aware标记接口。其设计目标是任何希望被注入MessageSource的 Bean都可以通过实现该接口由 Spring 容器在 Bean 生命周期中的特定阶段自动完成注入。MessageSource是 Spring 中用于国际化i18n的核心接口它提供了从不同消息资源如属性文件中按Locale获取消息的能力。借助它应用程序可以为一套代码提供多语言支持例如不同语言的错误提示、UI 标签或面向用户的其他文本。从源码结构看MessageSourceAware.java 源码 中 import 的org.springframework.context.MessageSourceAware接口定义非常精简只声明了一个回调方法public interface MessageSourceAware extends Aware { /** * 设置此对象运行的 MessageSource。 * 此方法在常规 bean 属性被填充之后调用但在初始化回调 * 如 InitializingBean 的 afterPropertiesSet 或自定义的 init-method之前调用。 * 此方法在 ApplicationContextAware 的 setApplicationContext 方法之前被调用。 */ void setMessageSource(MessageSource messageSource); }接口注释中还给出了一个重要提示由于MessageSource在应用上下文中通常以名为messageSource的 Bean 定义存在因此它也可以像普通 Bean 一样通过属性注入或构造函数参数传递MessageSourceAware则是更自动化、更明确的回调式获取方式。二、接口的三大核心功能结合 README 文档 与仓库实现MessageSourceAware主要提供以下能力自动注入当一个 Bean 实现了MessageSourceAware并被 Spring 容器管理时容器会自动调用其setMessageSource方法传入当前应用上下文的MessageSource实例无需任何 XML 或注解配置。国际化支持Bean 获得MessageSource引用后即可根据不同的地区与语言Locale获取相应消息这对需要展示多语言错误信息、UI 标签或其他面向用户文本的 Bean 尤其有用。简化配置相比常规依赖注入MessageSourceAware提供了一条自动化的获取路径特别适合 Bean 需要在初始化过程的特定阶段属性填充之后、初始化回调之前拿到MessageSource的场景。三、最佳实践完整可运行的国际化示例3.1 启动类入口仓库中的 MessageSourceAwareApplication.java 使用AnnotationConfigApplicationContext基于 Java 注解配置 Spring 容器的入口启动应用将MyConfiguration配置类作为构造参数传入随后从上下文中获取MyMessageSourceAwareBean 并调用其getMessage()方法public class MessageSourceAwareApplication { public static void main(String[] args) { AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(MyConfiguration.class); MyMessageSourceAware messageSourceAware context.getBean(MyMessageSourceAware.class); messageSourceAware.getMessage(); } }3.2 配置类注册 Bean 与 MessageSource仓库中的 MyConfiguration.java 使用ConfigurationBean定义了容器所需的两个 BeanConfiguration public class MyConfiguration { Bean public MyMessageSourceAware myMessageSourceAware(){ return new MyMessageSourceAware(); } Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource new ResourceBundleMessageSource(); messageSource.setBasename(i18n/messages); return messageSource; } }其中ResourceBundleMessageSource是 Spring 框架中用于国际化i18n的经典实现它基于java.util.ResourceBundle机制能够从类路径上的属性文件中读取国际化消息。关键配置项setBasename(i18n/messages)指定了属性文件的基本名称容器会按i18n/messages_ 语言地区后缀 的规则去寻找资源。3.3 国际化资源文件与本模块配套的属性文件位于仓库中messages_en.properties内容为greetingHello!messages_zh_CN.properties内容为greeting\u4f60\u597d即“你好”的 Unicode 转义形式这里特别值得注意属性文件编码问题.properties文件默认使用 ISO-8859-1 编码中文等非拉丁字符必须以\uXXXX形式做 Unicode 转义如\u4f60\u597d表示“你好”否则可能出现乱码。仓库中的中文属性文件正是这样处理的这也是文档“注意事项”中反复强调的实践要点。3.4 实现 MessageSourceAware 接口的 Bean仓库中的 MyMessageSourceAware.java 实现了MessageSourceAware在setMessageSource回调中保存注入的引用然后在getMessage()中按不同Locale检索消息public class MyMessageSourceAware implements MessageSourceAware { private MessageSource messageSource; Override public void setMessageSource(MessageSource messageSource) { this.messageSource messageSource; } public void getMessage() { System.out.println(EnglishmessageSource.getMessage(greeting, null, Locale.ENGLISH)); System.out.println(中文messageSource.getMessage(greeting, null, Locale.SIMPLIFIED_CHINESE)); } }messageSource.getMessage(greeting, null, Locale.ENGLISH)中的参数含义为code消息键、args占位符参数此处为 null、locale目标语言地区。运行后即可从对应属性文件取回消息。3.5 运行结果按上述配置执行MessageSourceAwareApplication控制台输出如下英文取自messages_en.properties中文取自messages_zh_CN.propertiesEnglishHello! 中文你好可见MyMessageSourceAware无需任何显式装配代码便已在容器初始化阶段拿到了MessageSource并成功完成了两种语言的消息检索。四、时序图MessageSourceAware 注入全流程文档用 Mermaid 时序图清晰勾勒了从应用启动到setMessageSource回调被触发的完整调用链本文将其整理为结构化流程该图描述了AnnotationConfigApplicationContext启动环境下的完整链路MessageSourceAwareApplication创建AnnotationConfigApplicationContext构造函数内部依次执行this()、register(componentClasses)、refresh()refresh()中先执行initMessageSource()保证上下文必有MessageSource再执行finishBeanFactoryInitialization(beanFactory)finishBeanFactoryInitialization调用DefaultListableBeanFactory#preInstantiateSingletons()对所有非懒加载单例 Bean 执行getBean(name)getBean委托给doGetBean经DefaultSingletonBeanRegistry#getSingleton(beanName, singletonFactory)走createBean→doCreateBean→initializeBeaninitializeBean调用applyBeanPostProcessorsBeforeInitialization最终由ApplicationContextAwareProcessor#postProcessBeforeInitialization命中MessageSourceAware并回调setMessageSource(messageSource)Bean 返回容器应用上下文初始化完成随后getMessage()即可使用注入的消息源。五、源码分析MessageSourceAware 的容器级注入链路5.1 入口AnnotationConfigApplicationContext 构造函数public AnnotationConfigApplicationContext(Class?... componentClasses) { this(); register(componentClasses); refresh(); }register(componentClasses)负责注册配置类而refresh()才是触发容器初始化的核心。下文重点追踪refresh()中的两个关键步骤。5.2 步骤一initMessageSource——保证 MessageSource 永远可用在org.springframework.context.support.AbstractApplicationContext#refresh方法中第一步即是初始化消息源Override public void refresh() throws BeansException, IllegalStateException { // ... [代码部分省略以简化] // 步骤1. Initialize message source for this context. initMessageSource(); // 步骤2. Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // ... [代码部分省略以简化] }initMessageSource()的实现逻辑保证了应用上下文始终存在一个可用的MessageSourceprotected void initMessageSource() { ConfigurableListableBeanFactory beanFactory getBeanFactory(); // 检查是否已存在名为 MESSAGE_SOURCE_BEAN_NAME 的 bean即 messageSource if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { // 存在则直接获取 this.messageSource beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // 若当前 MessageSource 支持层级且未设置父消息源 // 则将父上下文设为父 MessageSource if (this.parent ! null this.messageSource instanceof HierarchicalMessageSource) { HierarchicalMessageSource hms (HierarchicalMessageSource) this.messageSource; if (hms.getParentMessageSource() null) { hms.setParentMessageSource(getInternalParentMessageSource()); } } // ... [代码部分省略以简化] } else { // 不存在则注册默认实现 DelegatingMessageSource // 使 getMessage 调用总能被处理 DelegatingMessageSource dms new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); // ... [代码部分省略以简化] } }这段源码有两个关键结论显式配置优先只要容器中存在名为messageSourceMESSAGE_SOURCE_BEAN_NAME常量的 Bean就使用它这正是上一节MyConfiguration中Bean messageSource()生效的原因。默认兜底如果用户未定义Spring 会注册一个DelegatingMessageSource单例因此任何时刻调用context.getMessage()都是安全的。这也解释了文档“注意事项”中“确保我们的 Spring 上下文中有一个messageSourceBean通常命名为 messageSource”的提醒——命名约定是容器识别的关键。5.3 步骤二finishBeanFactoryInitialization——实例化全部非懒加载单例protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // ... [代码部分省略以简化] // 完成所有剩余非懒加载的单例 Bean 对象。 beanFactory.preInstantiateSingletons(); }DefaultListableBeanFactory#preInstantiateSingletons遍历所有 Bean 名称并逐一触发getBeanpublic void preInstantiateSingletons() throws BeansException { // ... [代码部分省略以简化] for (String beanName : beanNames) { getBean(beanName); } // ... [代码部分省略以简化] }由于MyConfiguration中注册的myMessageSourceAware是单例且非懒加载它便在这一步被实例化setMessageSource回调也随之发生。5.4 getBean → doGetBean → getSingletonBean 创建主链路AbstractBeanFactory#getBean委托给doGetBean(name, null, null, false)doGetBean对于单例 Bean 走getSingleton(beanName, singletonFactory)的 lambda 创建路径内部调用createBean(beanName, mbd, args)DefaultSingletonBeanRegistry#getSingleton在singletonObjects缓存未命中时通过singletonFactory.getObject()创建新实例并加锁保证线程安全。之后createBean再委托给真正干活的doCreateBean。5.5 doCreateBean → initializeBean进入初始化阶段AbstractAutowireCapableBeanFactory#doCreateBean中exposedObject initializeBean(beanName, exposedObject, mbd)是 Bean 初始化的关键一步。initializeBean中若 Bean 定义非合成!mbd.isSynthetic()会先调用protected Object initializeBean(String beanName, Object bean, Nullable RootBeanDefinition mbd) { // ... [代码部分省略以简化] Object wrappedBean bean; if (mbd null || !mbd.isSynthetic()) { wrappedBean applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } // ... [代码部分省略以简化] return wrappedBean; }applyBeanPostProcessorsBeforeInitialization遍历所有已注册的BeanPostProcessor逐个执行postProcessBeforeInitialization(result, beanName)任一处理器返回 null 则提前终止Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current processor.postProcessBeforeInitialization(result, beanName); if (current null) { return result; } result current; } return result; }5.6 关键一环ApplicationContextAwareProcessor 触发 Aware 回调在所有BeanPostProcessor中org.springframework.context.support.ApplicationContextAwareProcessor专门负责处理 Aware 系列接口。其postProcessBeforeInitialization首先做类型匹配筛选Override Nullable public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware || bean instanceof ApplicationStartupAware)) { return bean; } // ... [代码部分省略以简化] invokeAwareInterfaces(bean); return bean; }随后在invokeAwareInterfaces中完成实际注入private void invokeAwareInterfaces(Object bean) { // ... [代码部分省略以简化] if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } // ... [代码部分省略以简化] }注意一个细节这里传给setMessageSource的正是applicationContext自身AbstractApplicationContext实现了MessageSource接口其getMessage委托给内部持有的消息源。也就是说无论用户是否自定义了messageSourceBeanMessageSourceAwareBean 拿到的都是当前应用上下文这一“代理”消息源从而保证了注入的稳定性与父子上下文的可追溯性。5.7 最终执行用户自定义逻辑流程的终点是MyMessageSourceAware的getMessage()利用已注入的messageSource分别以Locale.ENGLISH与Locale.SIMPLIFIED_CHINESE检索greeting键并打印。整个注入过程对业务代码完全透明这正是 Aware 回调机制的典型价值。六、注意事项与实践建议结合 README 文档 与源码验证使用MessageSourceAware时有 7 个要点值得牢记明确的配置确保 Spring 上下文中存在一个通常命名为messageSource的 Bean。虽然 Spring 提供默认实现DelegatingMessageSource但要满足自定义需求如指定 basename 的属性文件必须显式配置。生命周期时机setMessageSource在常规属性填充之后、初始化回调InitializingBean#afterPropertiesSet或自定义init-method之前被调用不要在构造函数等早期阶段期望MessageSource已就绪。文档还明确指出该方法在ApplicationContextAware#setApplicationContext之前被调用。文件位置与命名使用ResourceBundleMessageSource时属性文件必须位于类路径上且 basename 需与配置严格匹配本模块为i18n/messages对应messages.properties、messages_en.properties、messages_zh_CN.properties等。编码问题属性文件默认 ISO-8859-1 编码包含中文、俄文等字符时必须使用 Unicode 转义如\u4f60\u597d或显式配置正确编码仓库中的中文属性文件即采用转义写法。父子上下文在 Web 等父子上下文场景中子上下文可以访问父上下文的MessageSource反之则不行需在正确的上下文中配置消息源。避免硬编码消息键与默认文本尽量放入属性文件统一管理便于后续新增语言或调整文案而不改动代码。默认消息调用getMessage时可为defaultMessage参数提供兜底文本在消息键缺失时避免异常。七、总结最佳实践总结启动类MessageSourceAwareApplication使用AnnotationConfigApplicationContext启动基于注解的应用加载MyConfiguration配置类获取MyMessageSourceAwareBean 后调用getMessage()。配置类MyConfiguration定义了两个 Bean——myMessageSourceAware与messageSource后者为ResourceBundleMessageSourcebasename 为i18n/messages。实现接口MyMessageSourceAware实现MessageSourceAware由容器在初始化阶段自动注入MessageSource通过setMessageSource。消息检索getMessage()以Locale.ENGLISH和Locale.SIMPLIFIED_CHINESE分别检索greeting键输出英文与简体中文两条国际化消息。运行结果程序成功从对应属性文件取回两种语言的消息Hello!与你好证明 Aware 注入链路完整可用。源码分析总结应用启动从MessageSourceAwareApplication进入AnnotationConfigApplicationContext初始化容器并加载配置。容器初始化构造函数依次执行register与refreshrefresh是容器初始化的核心枢纽。消息源初始化refresh中的initMessageSource()确保上下文必有MessageSource未显式定义时注册DelegatingMessageSource兜底。Bean 实例化finishBeanFactoryInitialization→preInstantiateSingletons触发所有非懒加载单例的创建。生命周期回调doCreateBean→initializeBean→applyBeanPostProcessorsBeforeInitialization构成了 BeanPostProcessor 的插件化执行时机。Aware 处理ApplicationContextAwareProcessor识别MessageSourceAware并回调setMessageSource(applicationContext)完成消息源注入。消息检索业务 Bean 中即可直接使用注入的MessageSource按Locale取消息实现国际化能力。进一步学习可在仓库中对照阅读相关 Aware 模块如 ApplicationContextAware 示例、ResourceLoaderAware 示例并结合 MessageSourceAware 模块源码 动手复现运行前请确保i18n/messages_en.properties与i18n/messages_zh_CN.properties位于类路径src/main/resources下。赞分享示例工程文档【免费下载链接】spring-reading涵盖了 Spring 框架的核心概念和关键功能包括控制反转IOC容器的使用面向切面编程AOP的原理与实践事务管理的方式与实现Spring MVC 的流程与控制器工作机制以及 Spring 中数据访问、安全、Boot 自动配置等方面的深入研究。此外它还包含了 Spring 事件机制的应用、高级主题如缓存抽象和响应式编程以及对 Spring 源码的编程风格与设计模式的深入探讨。项目地址https://gitcode.com/GitHub_Trending/sp/spring-reading点击查看免费下载相关推荐深入解析Spring TransactionAnnotationParser接口及其实现深入解析Spring TransactionAnnotationParser接口及其实现 引言 在Spring框架的事务管理体系中 TransactionAn示例工程文档SwiftUI-Agent-Skill无障碍专题让AI生成的SwiftUI兼容VoiceOver与Dynamic TypeSwiftUI Agent Skill无障碍专题让AI生成的SwiftUI兼容VoiceOver与Dynamic Type SwiftUI Agent Ski深入理解Spring-Reading项目中的DataSource接口深入理解Spring Reading项目中的DataSource接口 引言为什么需要DataSource 在传统的JDBC开发中我们通常使用 Driver示例工程文档上一篇CocoaLumberjack自定义日志轮转触发条件高级配置指南下一篇Chromeless终极Cookie管理指南获取、设置、删除全流程详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考