spring 使用外部属性文件

一、PropertyPlaceholderConfigurer

spring提供的PropertyPlaceholderConfigurer实现类能够使Bean在配置时引用外部属性文件。
PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessorBean接口,因而也是一个Bean工厂后处理器。


二、PropertyPlaceholderConfigurer的使用

1、xml配置及注解方式:

      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
pom.xml
name=zhangsan
age=23
my.properties
package test;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Driver {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("my.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
        System.out.println(user.getAge());
    }
}
class User {
    @Value("${name}")
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
java 类
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="classpath:my.properties"
        p:fileEncoding="utf-8"/>
    <!-- 开启包扫描,因为User类使用到了@Value注解;包扫描不支持裸体类上的注解 -->
    <context:component-scan base-package="test"/>
    <!-- 使用外部属性文件值赋值 -->
    <bean id="user" class="test.User" p:age="${age}"/>
</beans>
spring my.xml

PropertyPlaceholderConfigurer的其他属性:
locations:可以引入多个属性文件
fileEncoding:属性文件的编码格式
order:指定多个属性的优先级
placeholderPrefix:默认值为“${”,可以修改
placeholderSuffix:默认为“}”

除了使用<bean>声明PropertyPlaceholderConfigurer引入属性文件这种方式外,还可以使用另一种简洁的方式;但如果希望自定义一些额外的高级功能,如属性加密、使用数据库表来保存配置信息时,就必须使用<bean>声明PropertyPlaceholderConfigurer的方式

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 引入属性文件 -->
    <context:property-placeholder location="my.properties"/>
    <!-- 开启包扫描,因为User类使用到了@Value注解;包扫描不支持裸体类上的注解 -->
    <context:component-scan base-package="test"/>
    <!-- 使用外部属性文件值赋值 -->
    <bean id="user" class="test.User" p:age="${age}"/>
</beans>
spring my.xml

2、Java配置及注解方式:

      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
pom.xml
name=zhangsan
age=23
my.properties
package test;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Driver {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
        System.out.println(user.getAge());
    }
}
class User {
    @Value("${name}")
    private String name;
    @Value("${age}")
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
java类
package test;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@ComponentScan
public class MyConfig {
    @Bean
    public User user() {
        return new User();
    }
    @Bean
    public PropertyPlaceholderConfigurer PropertyPlaceholderConfigurer() {
        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
        configurer.setLocation(new ClassPathResource("my.properties"));
        return configurer;
    }

}
java 配置类

三、自定义PropertyPlaceholderConfigurer——支持加密

加密

如果属性信息是数据库用户名、密码等敏感信息,应该使用密文方式。虽说Web应用的客户端用户看不到服务器端的属性文件,但内部人员却可以轻易查看属性文件的内容,这样容易造成数据库访问权限的泄露。

实现

PropertyPlaceholderConfigurer类继承了PlaceholderConfigurerSupport,PlaceholderConfigurerSupport有几个protected的空实现的属性转换方法,专门用于在使用属性之前对属性值进行转换;
所以我们需要自定义PlaceholderConfigurerSupport的实现类并覆盖相应的属性转换方法来代替spring提供的PropertyPlaceholderConfigurer

信息的加密可分为对称和非对称两种方式,前者加密后可以解密还原,而后者不可以还原;MD5是非对称加密,DES是对称加密,这里使用DES方式。DES加密解密的关键是加密密钥。

demo

      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.3.16.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
      </dependency>
pom.xml
name=agyo9QHJ78MfJAfVsP+M2w==
age=ArphqsQ7cdE=
my.properties
package test;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class DESUtils {
    // 指定DES加密解密所用的密钥
    private static Key key;
    private static String KEY_STR = "myKey";
    static {
        try {
            KeyGenerator generator = KeyGenerator.getInstance("DES");
            generator.init(new SecureRandom(KEY_STR.getBytes()));
            key = generator.generateKey();
            generator = null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 对字符串进行DES加密,返回Base64编码的加密字符串
     */
    public static String getEncryptString(String str) {
        BASE64Encoder base64en = new BASE64Encoder();
        try {
            byte[] strBytes = str.getBytes("UTF8");
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptStrBytes = cipher.doFinal(strBytes);
            return base64en.encode(encryptStrBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 对Base64编码的加密字符串进行DES解密,返回解密后的字符串
     */
    public static String getDecryptString(String str) {
        BASE64Decoder base64De = new BASE64Decoder();
        try {
            byte[] strBytes = base64De.decodeBuffer(str);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptStrBytes = cipher.doFinal(strBytes);
            return new String(decryptStrBytes, "UTF8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 对入参的字符串加密,并打印密文
     */
    public static void main(String[] args) throws Exception {
        args = new String[]{"zhangsan", "23"};
        if (args == null || args.length < 1) {
            System.out.println("请输入要加密的字符,用空格分隔.");
        } else {
            for (String arg : args) {
                System.out.println(arg + ":" + getEncryptString(arg));
            }
        }
        
        //System.out.println(getDecryptString("WnplV/ietfQ="));
        //System.out.println(getDecryptString("gJQ9O+q34qk="));
    }
}
DESUtils.java
package test;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Driver {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
        System.out.println(user.getAge());
    }
}
class User {
    @Value("${name}")
    private String name;
    @Value("${age}")
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
Driver.java 
package test;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

public class MyPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
    // 需要解密的属性
    private String[] encryptPropNames ={"name","age"};

    // 解密
    @Override
    protected String convertProperty(String propertyName, String propertyValue) {        
        if(isEncryptProp(propertyName)){
            String decryptValue = DESUtils.getDecryptString(propertyValue);
            System.out.println(decryptValue);
            return decryptValue;
        }else{
            return propertyValue;
        }
    }
    
    /**
     * 判断是否是加密的属性
     */
    private boolean isEncryptProp(String propertyName){
        for(String encryptPropName:encryptPropNames){
            if(encryptPropName.equals(propertyName)){
                return true;
            }
        }
        return false;
    }
}
自定义属性文件加载器
package test;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@ComponentScan // 因为用到了@Value注解,所以需要开启扫描
public class MyConfig {
    @Bean
    public User user() {
        return new User();
    }
//    @Bean
////    public PropertyPlaceholderConfigurer PropertyPlaceholderConfigurer() {
////        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
////        configurer.setLocation(new ClassPathResource("my.properties"));
////        return configurer;
////    }
    @Bean
    public MyPropertyPlaceholderConfigurer encryptPropertyPlaceholderConfigurer() {
        MyPropertyPlaceholderConfigurer configurer = new MyPropertyPlaceholderConfigurer();
        configurer.setLocation(new ClassPathResource("my.properties"));
        return configurer;
    }
}
java配置类

四、属性文件引用属性文件的属性值

Spring允许在xml、java类中使用${xxx}、@Value("${xxx}")引用属性值,也允许在属性文件中使用${xxx}引用其它属性文件的属性值
name=lisi
age=${age}
my.properties
age=18
my2.properties
package test;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
public class MyConfig {
    @Bean
    public User user() {
        return new User();
    }
    @Bean
    public PropertyPlaceholderConfigurer PropertyPlaceholderConfigurer() {
        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
        configurer.setLocations(new ClassPathResource[] {new ClassPathResource("my.properties"),
                                new ClassPathResource("my2.properties")});
        return configurer;
    }
}
MyConfig.java

  

原文地址:https://www.cnblogs.com/Mike_Chang/p/10276303.html