ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Spring 注入 Properties 详解

Spring 注入 Properties 详解 Spring 注入 Properties 详解一、什么是 Properties 注入java.util.Properties是 Java 标准库中用于存储键值对的类它的键和值都是String类型。在 Spring 中Properties 注入是指将一组配置以Properties对象的形式注入到 Bean 中。Properties 与 Map 的区别在于Properties 的键和值都是字符串且它本身提供了getProperty()、load()、store()等操作方法适合处理配置文件相关的场景。ComponentpublicclassMyBean{privatePropertiesconfigs;// 配置属性privatePropertiesmailConfig;// 邮件配置}二、XML 配置中注入 Properties2.1 使用props标签beanidmyBeanclasscom.example.MyBeanpropertynameconfigspropspropkeytimeout30/proppropkeyretry3/proppropkeydebugtrue/prop/props/property/beanprops是 XML 中专门用于注入 Properties 的标签等价于PropertiesconfigsnewProperties();configs.setProperty(timeout,30);configs.setProperty(retry,3);configs.setProperty(debug,true);2.2 注入对象类型的值如果需要注入非 String 类型的值使用map而不是propsbeanidmyBeanclasscom.example.MyBeanpropertynameconfigsmapentrykeytimeoutvalue30/entrykeymaxSizevalue1024//map/property/beanmap允许键和值是任意类型Spring 会进行类型转换。而props只支持 String 到 String。2.3 引用外部 Properties 文件通过util:命名空间加载外部 Properties 文件beansxmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:utilhttp://www.springframework.org/schema/utilxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd!-- 加载 classpath 下的 properties 文件 --util:propertiesidappConfiglocationclasspath:app.properties/!-- 注入到 Bean 中 --beanidmyBeanclasscom.example.MyBeanpropertynameconfigsrefappConfig//bean/beansapp.propertiesapp.namemyapp app.timeout30 app.debugtrue2.4 使用 PropertyPlaceholderConfigurer老项目常用PropertyPlaceholderConfigurer加载 Properties 文件并支持在 XML 中使用${}占位符beanclassorg.springframework.beans.factory.config.PropertyPlaceholderConfigurerpropertynamelocationslistvalueclasspath:app.properties/valuevalueclasspath:db.properties/value/list/property/beanbeaniddataSourceclasscom.zaxxer.hikari.HikariDataSourcepropertynamejdbcUrlvalue${db.url}/propertynameusernamevalue${db.username}/propertynamepasswordvalue${db.password}//beanSpring Boot 中这个类已被PropertySourcesPlaceholderConfigurer取代自动配置。三、注解方式注入 Properties3.1 使用 PropertySource 加载 Properties 文件ConfigurationPropertySource(classpath:app.properties)publicclassAppConfig{AutowiredprivateEnvironmentenvironment;BeanpublicPropertiesappConfig(){PropertiespropsnewProperties();props.setProperty(app.name,environment.getProperty(app.name));props.setProperty(app.timeout,environment.getProperty(app.timeout));returnprops;}}这种方式比较繁琐需要逐个从Environment中读取。更好的方式是使用ConfigurationProperties或Value。3.2 使用 Value 注入单个属性ComponentPropertySource(classpath:app.properties)publicclassMyBean{Value(${app.name})privateStringappName;Value(${app.timeout:30})privateinttimeout;}Value适合单个属性的注入不适合批量注入。3.3 使用 ConfigurationProperties 批量绑定ComponentConfigurationProperties(prefixapp)GetterSetterpublicclassAppProperties{privateStringname;privateinttimeout;privatebooleandebug;privatePropertiesextra;// 嵌套 Properties}# app.properties app.namemyapp app.timeout30 app.debugtrue app.extra.key1value1 app.extra.key2value2或者使用 YAMLapp:name:myapptimeout:30debug:trueextra:key1:value1key2:value2ConfigurationProperties支持将配置绑定到Properties类型的字段但要求配置的结构清晰。四、直接注入 Properties Bean在 Spring Boot 中可以通过Bean定义一个 Properties 类型的 Bean然后注入到需要的地方。4.1 定义 Properties BeanConfigurationpublicclassPropertiesConfig{Bean(mailProperties)publicPropertiesmailProperties(){PropertiespropsnewProperties();props.setProperty(mail.host,smtp.example.com);props.setProperty(mail.port,587);props.setProperty(mail.username,noreplyexample.com);props.setProperty(mail.password,secret);returnprops;}}4.2 注入使用ServicepublicclassMailService{AutowiredQualifier(mailProperties)privatePropertiesmailProperties;publicvoidsend(Stringto){StringhostmailProperties.getProperty(mail.host);StringportmailProperties.getProperty(mail.port);// 发送邮件}}如果容器中只有一个Properties类型的 Bean可以省略Qualifier。如果有多个必须通过名称区分。4.3 从配置文件加载到 Properties BeanConfigurationpublicclassAppConfig{BeanpublicPropertiesappConfig()throwsIOException{PropertiespropsnewProperties();try(InputStreamisnewClassPathResource(app.properties).getInputStream()){props.load(is);}returnprops;}}4.4 使用 PropertySource Bean 组合ConfigurationPropertySource(classpath:app.properties)publicclassAppConfig{AutowiredprivateEnvironmentenvironment;BeanpublicPropertiesappProperties(){PropertiespropsnewProperties();// 读取所有 app. 开头的配置for(Stringkey:Arrays.asList(app.name,app.timeout,app.debug)){Stringvalueenvironment.getProperty(key);if(value!null){props.setProperty(key,value);}}returnprops;}}这种方式适合需要把一组配置以 Properties 对象的形式传给第三方库的场景。五、Properties 注入的底层原理Spring 在注入 Properties 时会根据目标类型选择合适的转换策略XML 配置propsSpring 解析props标签时创建Properties对象将prop中的键值对逐个setProperty()。这是 Spring 内部直接构造的 Properties 实例。ConfigurationProperties 绑定如果字段类型是PropertiesSpring 的PropertiesConfigurationFactory或Binder会递归处理嵌套配置将嵌套的键值对展平后存入 Properties 对象。自动注入 Properties Bean如果容器中存在Properties类型的 BeanAutowired按类型注入。Properties本身是一个Hashtable的子类Spring 将其作为普通 Bean 管理。六、Properties vs Map vs ConfigurationProperties对比维度PropertiesMapConfigurationProperties键值类型仅 String任意类型任意类型是否支持嵌套展平为字符串键支持嵌套 Map支持嵌套对象类型安全弱需手动转换中强适用场景与传统 Properties 文件对接简单键值对结构化配置配置文件绑定需手动处理ConfigurationProperties原生支持选择建议需要将配置传递给第三方库如 JavaMail、数据源时用 Properties需要结构化、类型安全的配置时用ConfigurationProperties简单的键值对且不需要嵌套时用 Map 也可以七、常见问题7.1 XML 中props和map混用!-- ❌ 错误Properties 属性不能用 map 注入非 String 值 --propertynameconfigsmapentrykeytimeoutvalue30//map/property如果属性类型是Properties应该用props。map适用于Map类型。7.2 ConfigurationProperties 绑定 Properties 失败原因Properties 的键必须是 String如果配置中有复杂的嵌套结构绑定可能失败。解决对于复杂结构改用MapString, Object或自定义对象。7.3 多个 Properties Bean 注入冲突原因容器中有多个Properties类型的 BeanAutowired无法确定注入哪一个。解决使用Qualifier(beanName)指定具体名称。AutowiredQualifier(mailProperties)privatePropertiesmailProperties;7.4 Properties 文件中的中文乱码原因Properties.load()默认使用 ISO-8859-1 编码。解决使用load(Reader)并指定 UTF-8PropertiespropsnewProperties();try(ReaderreadernewInputStreamReader(newClassPathResource(app.properties).getInputStream(),StandardCharsets.UTF_8)){props.load(reader);}或者直接使用ConfigurationPropertiesSpring Boot 会正确处理编码。7.5 注入的 Properties 是只读的原因Value注入的属性是只读的无法动态修改。解决如果需要动态修改配置使用ConfigurationProperties配合RefreshScope或注入Environment手动获取。八、最佳实践优先使用 ConfigurationProperties。在 Spring Boot 项目中结构化配置用ConfigurationProperties绑定最自然类型安全且支持嵌套。需要传递 Properties 给第三方库时用 Properties Bean。比如 JavaMail 的JavaMailSenderImpl、数据源的配置等第三方库通常接受 Properties 参数。避免用 Value 批量注入。如果有一组配置需要注入用ConfigurationProperties而不是多个Value。注意 Properties 的编码。使用 UTF-8 加载 Properties 文件避免中文乱码。多个 Properties Bean 用 Qualifier 区分。为不同的 Properties Bean 指定清晰的名称注入时明确指定。九、总结维度核心要点XML 注入使用props标签或用util:properties加载外部文件Value 注入适合单个属性不适合批量注入ConfigurationProperties批量绑定配置到对象支持嵌套 PropertiesProperties Bean通过Bean定义AutowiredQualifier注入键值类型Properties 的键和值都是 String编码使用 UTF-8 加载避免中文乱码多 Bean 冲突使用Qualifier指定名称最佳实践结构化配置用ConfigurationProperties第三方库对接用 Properties BeanProperties 注入在 Spring 中主要用于两类场景一是与传统 Properties 文件对接二是将配置以 Properties 对象的形式传递给第三方库。在 Spring Boot 项目中日常的配置管理更推荐用ConfigurationPropertiesProperties 注入更多出现在需要兼容旧代码或对接第三方库的场景中。
返回列表