Spring-使用外部属性文件01

简介: Spring-使用外部属性文件01

导读


Spring-使用外部属性文件01

Spring-使用加密的属性文件02

Spring-属性文件自身的引用03


概述


在进行数据源或者邮件服务器等资源配置时,用户可以直接在Spring配置文件中配置用户名、密码、连接信息等,但是有一种更好的方法是将这些配置信息独立到一个外部属性文件中,并在Spring配置文件中通过形如${user}、${password}的占位符引用属性文件中的属性项。


通过这种方式配置拥有两个明显的好处


减少维护的工作量

部署更加简单

Spring提供了一个PropertyPlaceholderConfigurer,它能够使Bean在配置时引用外部属性文件。


PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessorBean接口,因而也是一个Bean工厂后处理器.


PropertyPlaceholderConfigurer属性文件


代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


实例


maven项目


20170807045841538.jpg


一种不太好的写法

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@172.25.246.11:1521:xgj"/>
        <property name="username" value="cctb"/>
        <property name="password" value="xgj2017"/>
    </bean>



从上面的配置文件中,我们可以看到驱动器类名、JDBC的URL以及数据库的用户名和密码都写在了XML中。部署的时候,如果需要改动数据库的配置信息,需要先找到这个xml,然后修改,不是特别方便。


根据实际应用的最佳实践,我们可以将这些信息抽取到一个配置文件中,取名为 jdbc.priperties (随意取名)

我们先看下jdbc.priperties的配置文件

jdbc.properties

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@172.25.246.11:1521:xgj
jdbc.username=cctb
jdbc.password=xgj2017


属性文件可以定义多个属性,每个属性都有一个属性名和属性值组成,二者用“=”隔开。

使用PropertyPlaceholderConfigurer属性文件


下面通过PropertyPlaceholderConfigurer引入jdbc.properties属性文件,调整数据源Bean的配置,为了测试,我们引入了JdbcTemplate

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <context:component-scan base- package="com.xgj.ioc.propertyplacehoder"/>
    <!-- 引入JDBC属性文件 -->
    <bean  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="classpath:spring/jdbc.properties"
        p:fileEncoding="utf-8"/>
    <!-- 通过属性名引用属性值 -->     
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.url}"
        p:username="${jdbc.username}"
        p:password="${jdbc.password}"/>
    <!-- 配置Jdbc模板  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dataSource" />
</beans>

通过PropertyPlaceholderConfigurer的location属性引入属性文件,这样在Bean定义的时候就可以引用属性文件中的属性了。


然后通过${jdbc.driverClassName}等占位符来引用jdbc.properties中的属性,这样部署人员仅需要关注jdbc.properties这个配置文件即可,无需关心Spring的配置文件。


测试:


我们数据库中temp_user表有一条记录,我们来模拟登录查询



20170807051317524.jpg

PropertyPlaceHoderTest.java

package com.xgj.ioc.propertyplacehoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class PropertyPlaceHoderTest {
    private final static String MATCH_COUNT_SQL = " SELECT count(*) FROM temp_user  "
            + " WHERE user_name =? and password=? ";
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    /**
     * 
     * 
     * @Title: getMatchCount
     * 
     * @Description: 根据用户名和密码判断用户是否存在
     * 
     * @param username
     * @param password
     * 
     * @return: int
     */
    public int getMatchCount(String username, String password) {
        return jdbcTemplate.queryForObject(MATCH_COUNT_SQL, new Object[] {
                username, password }, Integer.class);
    }
    /**
     * 
     * 
     * @Title: main
     * 
     * @Description: 测试
     * 
     * @param args
     * 
     * @return: void
     */
    public static void main(String[] args) {
        // 加载Spring配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/propertyplacehoder/beans.xml");
        // 获取通过注解标注的Bean
        PropertyPlaceHoderTest propertyPlaceHoderTest = ctx.getBean(
                "propertyPlaceHoderTest", PropertyPlaceHoderTest.class);
        // 调用方法
        int count = propertyPlaceHoderTest.getMatchCount("xgj", "123456");
        System.out.println("匹配的用户数量:" + count);
    }
}


运行结果:


20170807051406071.jpg


PropertyPlacerholderConfigurer的其他属性

locations

如果只有一个属性文件,则直接使用location属性指定即可,如果有多个属性文件,则可以通过locations属性进行设置,可以像配置list一样配置locations属性。

list的配置参考 Spring-注入参数详解-[集合类型属性]


fileEncoding

属性文件的编码格式,Spring默认使用操作系统默认编码读取属性文件,如果属性文件使用了特殊编码,则需要通过该属性显式指定。

order

如果配置配置文件中定义了多个PropertyPlacehoderConfigurer,则通过该属性指定优先顺序。


placeholderPrefix

上面的案例,我们使用${jdbc.driverClassName}引用属性文件中的属性项, 其中, ${ 为默认的占位符前缀,可修改


placeholderSuffix

占位符后缀,默认为 }


使用context:property-placehoder引用属性文件

可以使用context命名空间定义属性文件,相比传统的PropertyPlaceholderConfigurer配置,这种方式更优雅

<!-- 引入JDBC属性文件
    <bean  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="classpath:spring/jdbc.properties"
        p:fileEncoding="utf-8"/>  -->
    <!-- 使用context命名空间,同上面的Bean等效。 -->
     <context:property-placeholder location="classpath:spring/jdbc.properties" />

但是有个缺点: 如果想自定义一些额外的高级功能,比如属性加密、使用数据库表保存配置信息等,则必须扩展PropertyPlaceholderConfigurer的类并使用Bean的配置方式。


基于注解及基于JAVA类的配置中引用属性


在基于XML的配置文件中,通过${propName}的形式引用属性值,类似的,基于注解的Bean可以通过@Value注解为Bean的成员变量或者方法入参自动注入容器已有的属性。同样的基于JAVA类注解@Configuration的类的引用属性的方式和基于注解配置的引用方式是完全一样的,不再赘述。


实例


20170807061946127.jpg

package com.xgj.ioc.propertyplacehoder.annotation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class MyDataSource {
    private String driveClassName;
    private String url;
    private String userName;
    private String password;
    /**
     * 
     * 
     * @Title: setDriveClassName
     * 
     * @Description: 注入jdbc.driverClassName的值 (也可以直接在属性上注入)
     * 
     * @param driveClassName
     * 
     * @return: void
     */
    @Value("${jdbc.driverClassName}")
    public void setDriveClassName(String driveClassName) {
        this.driveClassName = driveClassName;
    }
    @Value("${jdbc.url}")
    public void setUrl(String url) {
        this.url = url;
    }
    @Value("${jdbc.username}")
    public void setUserName(String userName) {
        this.userName = userName;
    }
    @Value("${jdbc.password}")
    public void setPassword(String password) {
        this.password = password;
    }
    /**
     * 
     * 
     * @Title: getDriveClassName
     * 
     * @Description: 获取driveClassName
     * 
     * @return
     * 
     * @return: String
     */
    public String getDriveClassName() {
        System.out.println("getDriveClassName:" + driveClassName);
        return driveClassName;
    }
    public String getUrl() {
        System.out.println("getUrl:" + url);
        return url;
    }
    public String getUserName() {
        System.out.println("getUserName:" + userName);
        return userName;
    }
    public String getPassword() {
        System.out.println("getPassword:" + password);
        return password;
    }
}

测试类

package com.xgj.ioc.propertyplacehoder.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/propertyplacehoder/beans.xml");
        MyDataSource myDataSource = ctx.getBean("myDataSource",
                MyDataSource.class);
        myDataSource.getDriveClassName();
        myDataSource.getUrl();
        myDataSource.getUserName();
        myDataSource.getPassword();
    }
}


运行结果

20170807062109614.jpg


注意事项


使用的过程中,一定要确保所引用的属性值在属性文件中存在且数值匹配,否则会造成Bean创建错误。

比如我们修改一下注入的属性@Value(“${jdbc.driverClassName1}”)


Error creating bean with name ‘myDataSource’: Injection of autowired dependencies failed; …..

2017-08-06 18:23:17,692  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7fae1081: startup date [Sun Aug 06 18:23:17 BOT 2017]; root of context hierarchy
2017-08-06 18:23:17,767  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/ioc/propertyplacehoder/beans.xml]
2017-08-06 18:23:18,398  WARN [main] (AbstractApplicationContext.java:551) - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDataSource': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'jdbc.driverClassName1' in value "${jdbc.driverClassName1}"
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDataSource': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'jdbc.driverClassName1' in value "${jdbc.driverClassName1}"
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.xgj.ioc.propertyplacehoder.annotation.AnnotationTest.main(AnnotationTest.java:9)
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jdbc.driverClassName1' in value "${jdbc.driverClassName1}"
    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
    at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)
    at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:831)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:659)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    ... 13 more


相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
91 2
|
12天前
|
Java Spring
【Spring配置】创建yml文件和properties或yml文件没有绿叶
本文主要针对,一个项目中怎么创建yml和properties两种不同文件,进行配置,和启动类没有绿叶标识进行解决。
|
5月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
6月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。
|
7月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
77 0
|
3月前
|
存储 前端开发 Java
Spring Boot 集成 MinIO 与 KKFile 实现文件预览功能
本文详细介绍如何在Spring Boot项目中集成MinIO对象存储系统与KKFileView文件预览工具,实现文件上传及在线预览功能。首先搭建MinIO服务器,并在Spring Boot中配置MinIO SDK进行文件管理;接着通过KKFileView提供文件预览服务,最终实现文档管理系统的高效文件处理能力。
468 11
|
3月前
|
Java Maven Spring
用Spring导致的无法运行Java文件的问题的解决方案
本文提供了解决在IntelliJ IDEA社区版中使用Spring Initializr插件创建Spring项目后,Java文件无法运行的问题的方法,主要是通过加载Maven项目来解决。
91 0
|
5月前
|
Java Spring 开发者
Spring 框架配置属性绑定大比拼:@Value 与 @ConfigurationProperties,谁才是真正的王者?
【8月更文挑战第31天】Spring 框架提供 `@Value` 和 `@ConfigurationProperties` 两种配置属性绑定方式。`@Value` 简单直接,适用于简单场景,但处理复杂配置时略显不足。`@ConfigurationProperties` 则以类级别绑定配置,简化代码并更好组织配置信息。本文通过示例对比两者特点,帮助开发者根据具体需求选择合适的绑定方式,实现高效且易维护的配置管理。
77 0
|
5月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
57 0
|
5月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?

热门文章

最新文章