问题背景
最近在 Spring MVC 项目中集成邮件发送功能时,遇到了通过@Value注解从*.properties文件读取配置值的问题。在单元测试junit中可以正常获取,但在业务代码中却获取到null。
解决方案:使用 @Value 注解读取配置
Spring 除了传统的 XML 配置方式外,还可以通过@Value注解来获取*.properties文件中的配置值。
1. 配置实体类
@Value注解需要 Spring 的注解扫描支持,因此需要在 Spring 配置中扫描实体类所在的包,并在实体类上添加@Component注解。
@Component public class MailBean { // 实体类添加 @Component,让 Spring 扫描并管理,默认单例模式 // 功能:从 data.properties 资源文件中读取邮件配置 @Value("#{configProperties['emailhost']}") private String emailHost; @Value("#{configProperties['emailform']}") private String emailFrom; @Value("#{configProperties['emailname']}") private String emailUsername; @Value("#{configProperties['emailpassword']}") private String emailPassword; // Getter 方法 public String getEmailHost() { return emailHost; } public String getEmailFrom() { return emailFrom; } public String getEmailUsername() { return emailUsername; } public String getEmailPassword() { return emailPassword; } }2. Spring 配置文件
在applicationContext.xml中配置组件扫描和属性文件加载:
<!-- 自动扫描 com.myweb 包,将带有注解的类纳入 Spring 容器管理 --> <context:component-scan base-package="com.myweb"></context:component-scan> <!-- 引入配置文件 --> <bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="locations"> <list> <value>classpath:data.properties</value> <value>classpath:application.properties</value> </list> </property> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="properties" ref="configProperties" /> </bean>3. 属性文件配置
data.properties文件内容:
emailhost=邮箱的网关 emailname=你的用户名 emailpassword=你的密码 emailform=发件邮箱 // 具体值需根据自身情况配置问题现象与排查
单元测试正常
通过 JUnit 测试可以正常获取配置值:
@Test public void test() { ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml"); MailBean connInfo = appContext.getBean(MailBean.class); System.out.println(connInfo.getEmailHost()); System.out.println(connInfo.getEmailFrom()); System.out.println(connInfo.getEmailUsername()); // 可以正常获取 }业务代码中获取 null
但在具体业务代码中使用时,获取到的却是null。
问题原因与解决方案
问题原因
在业务代码中,仍然使用new MailBean()来创建对象。但MailBean已经通过@Component注解加入了 Spring 容器的管理,并且默认是单例模式。直接new创建的对象不会被 Spring 管理,因此@Value注解不会生效。
正确做法
在业务类中通过依赖注入的方式获取MailBean实例:
@Resource private MailBean mailBean;同时,业务类本身也需要交给 Spring 管理(添加相应的注解,如@Controller、@Service、@Repository或@Component)。
在 JUnit 测试中,通过appContext.getBean(MailBean.class)获取的是 Spring 容器管理的 Bean,所以能正常取值。在业务代码中,必须通过@Resource或@Autowired注入,否则无法获取到正确的 Bean。
常见警告及处理
在 Spring 配置文件中添加上述配置时,可能会遇到以下警告:
警告:Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKey ...该警告是由于写入注册表时权限不足引起的。解决方法:
- 打开命令窗口,输入
regedit打开注册表管理器 - 导航到
HKEY_LOCAL_MACHINE\Software\JavaSoft\ - 在
JavaSoft下创建Prefs项即可
总结
通过@Value注解读取*.properties配置时需要注意:
- 实体类需要添加
@Component等 Spring 管理注解 - Spring 配置中需要扫描实体类所在的包
- 在业务代码中必须通过依赖注入获取 Bean,不能直接
new创建 - 遇到注册表权限警告时,手动创建相应的注册表项即可解决