TA的每日心情 | 无聊 9 小时前 |
---|
签到天数: 1052 天 连续签到: 2 天 [LV.10]测试总司令
|
简介
从Spring Boot 1.3开始,我们可以在应用程序上下文刷新之前使用EnvironmentPostProcessor来自定义应用程序的Environment。Environment表示当前应用程序运行的环境,它可以统一访问各种属性源中的属性,如属性文件、JVM系统属性、系统环境变量和Servlet上下文参数。使用EnvironmentPostProcessor可以在bean初始化之前对Environment进行修改。
使用示例
让我们设想一个需求,配置文件中的数据库密码是加密后的密文,如:
- spring.datasource.password=js8sbAwkduzPTEWQrlDbTw==
复制代码 在应用启动时,对密文进行解密后再进行数据库的连接。
针对这种需求,就可以通过EnvironmentPostProcessor对密文进行解密,重新放到Environment中。
1.实现EnvironmentPostProcessor
package one.more;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import java.util.Properties;
public class DecodeEnvironmentPostProcessor implements EnvironmentPostProcessor {
public static final String SPRING_DATASOURCE_PASSWORD = "spring.datasource.password";
public static final String AES_SECRET = "OneMore";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String password = environment.getProperty(SPRING_DATASOURCE_PASSWORD);
Properties properties = new Properties();
properties.setProperty(SPRING_DATASOURCE_PASSWORD, AESUtil.decrypt(password, AES_SECRET));
PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource(SPRING_DATASOURCE_PASSWORD,
properties);
environment.getPropertySources().addFirst(propertiesPropertySource);
}
}
如果你希望EnvironmentPostProcessor按照特定的顺序被调用,可以实现Ordered接口,或者使用@Order注解。
2.注册实现类
想要在Spring Boot启动过程中调用这个实现类,我们还需要在META-INF/ Spring .factories中注册这个实现类:
- org.springframework.boot.env.EnvironmentPostProcessor=
- one.more.DecodeEnvironmentPostProcessor
复制代码 单元测试
下面介绍本文的重点:怎么做EnvironmentPostProcessor实现类的单元测试,话不多说,直接上代码:
- package one.more;
- import org.junit.Assert;
- import org.junit.Test;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.WebApplicationType;
- import org.springframework.boot.builder.SpringApplicationBuilder;
- import org.springframework.boot.env.EnvironmentPostProcessor;
- import org.springframework.context.ConfigurableApplicationContext;
- import org.springframework.core.env.ConfigurableEnvironment;
- import org.springframework.core.env.PropertiesPropertySource;
- import java.util.Properties;
- public class DecodeEnvironmentPostProcessorTest {
- @Test
- public void testPostProcessEnvironment() {
- DecodeEnvironmentPostProcessor processor = new DecodeEnvironmentPostProcessor();
- String password = "one-more";
- Properties properties = new Properties();
- properties.setProperty(DecodeEnvironmentPostProcessor.SPRING_DATASOURCE_PASSWORD,
- AESUtil.encrypt(password, DecodeEnvironmentPostProcessor.AES_SECRET));
- ConfigurableEnvironment environment = getEnvironment(processor, properties);
- Assert.assertEquals(password,
- environment.getProperty(DecodeEnvironmentPostProcessor.SPRING_DATASOURCE_PASSWORD));
- }
- /**
- * 获取一个经过EnvironmentPostProcessor处理过的Environment
- *
- * @param processor EnvironmentPostProcessor实现类的实例
- * @param properties 预置准备做单元测试的属性
- * [url=home.php?mod=space&uid=26358]@return[/url] 处理过的Environment
- */
- private ConfigurableEnvironment getEnvironment(EnvironmentPostProcessor processor, Properties properties) {
- // 创建一个SpringApplication
- SpringApplication springApplication = new SpringApplicationBuilder()
- .sources(DecodeEnvironmentPostProcessor.class)
- .web(WebApplicationType.NONE).build();
- // 获取应用上下文
- ConfigurableApplicationContext context = springApplication.run();
- // 获取Environment
- ConfigurableEnvironment environment = context.getEnvironment();
- //添加准备做单元测试的属性
- environment.getPropertySources()
- .addFirst(new PropertiesPropertySource("test", properties));
- processor.postProcessEnvironment(environment, springApplication);
- context.close();
- return environment;
- }
- }
复制代码 附:加解密工具类代码
package one.more;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class AESUtil {
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
private static final String KEY_ALGORITHM = "AES";
public static String encrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
byte[] result = cipher.doFinal(byteContent);
return Base64.encodeBase64String(result);
} catch (Exception ex) {
}
return null;
}
public static String decrypt(String content, String password) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, "utf-8");
} catch (Exception ex) {
}
return null;
}
private static SecretKeySpec getSecretKey(final String password) {
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
kg.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
} catch (NoSuchAlgorithmException ex) {
}
return null;
}
}
|
|