简介

从Spring Boot 1.3开始,我们可以在应用程序上下文刷新之前使用EnvironmentPostProcessor来自定义应用程序的Environment。Environment表示当前应用程序运行的环境,它可以统一访问各种属性源中的属性,如属性文件、JVM系统属性、系统环境变量和Servlet上下文参数。使用EnvironmentPostProcessor可以在bean初始化之前对Environment进行修改。

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

使用示例

让我们设想一个需求,配置文件中的数据库密码是加密后的密文,如:

spring.datasource.password=js8sbAwkduzPTEWQrlDbTw==

在应用启动时,对密文进行解密后再进行数据库的连接。

针对这种需求,就可以通过EnvironmentPostProcessor对密文进行解密,重新放到Environment中。

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

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

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

单元测试

下面介绍本文的重点:怎么做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 预置准备做单元测试的属性
* @return 处理过的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;
}
}

文章持续更新,微信搜索「万猫学社」第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

附:加解密工具类代码

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;
}
}

微信公众号:万猫学社

微信扫描二维码

关注后回复「电子书」

获取12本Java必读技术书籍

EnvironmentPostProcessor怎么做单元测试?阿里P7解答的更多相关文章

  1. 阿里P7终于讲完了JDK+Spring+mybatis+Dubbo+SpringMvc+Netty源码

    前言 这里普及一下,每个公司都有职别定级系统,阿里也是,技术岗以 P 定级,一般校招 P5, 社招 P6 起.其实阅读源码也是有很多诀窍的,这里分享几点心得: 首先要会用.你要知道这个库是干什么的,掌 ...

  2. 转头条:阿里p7架构师:三年经验应该具备什么样的技能?

    问:工作中,有时候实现一个功能,会去看有没有现成的轮子可用.对于重复造轮子与改造轮子有什么看法? 答:一定会的,其实这也是一个提高技术能力的方法,比如今天想做个日期转换的功能,JDK8有日期的新特性就 ...

  3. 跟着阿里p7一起学java高并发 - 第18天:玩转java线程池,这一篇就够了

    java中的线程池,这一篇就够了 java高并发系列第18篇文章. 本文主要内容 什么是线程池 线程池实现原理 线程池中常见的各种队列 自定义线程创建的工厂 常见的饱和策略 自定义饱和策略 线程池中两 ...

  4. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...

  5. 阿里P7岗位面试,面试官问我:为什么HashMap底层树化标准的元素个数是8

    前言 先声明一下,本文有点标题党了,像我这样的菜鸡何德何能去面试阿里的P7岗啊,不过,这确实是阿里p7级岗位的面试题,当然,参加面试的人不是我,而是我部门的一个大佬.他把自己的面试经验分享给了我,也让 ...

  6. 身边好几个技术一般的程序员都面上了,阿里P7门槛降低?

    经常在网上的论坛里看到讨论程序员的级别,尤其在跳槽类的信息里可以看到对标阿里P7,百度T6,腾讯3.1等字眼,似乎大厂的级别俨然可以成为业内的通用货币,类似于高考分数一样,哪一档就对应着什么样的待遇. ...

  7. spring junit 做单元测试,报 Failed to load ApplicationContext 错误

    spring junit 做单元测试,报 Failed to load ApplicationContext 错误. 查找了好一会,最后发现.@ContextConfiguration(locatio ...

  8. 使用python做你自己的自动化测试--对Java代码做单元测试 (2)-导入第三方jar包裹

    使用Jython对Java做单元测试,当然,为了测试开发java代码.这涉及到引入第三包的问题,如何导入第三方的包? 您可以使用http://blog.csdn.net/powerccna/artic ...

  9. 使用karma+jasmine做单元测试

    目的 使用karma和jasmine来配置自动化的js单元测试. Karma和Jasmine Karma是由Angular团队所开发的一种自动化测试工具.链接:http://karma-runner. ...

随机推荐

  1. 使用MDNS进行局域网服务发现(.NET Core)

    使用MDNS进行局域网服务发现(.NET Core) 想要服务写的好,配置文件不可少.如果是一个复杂的系统,甚至配置文件都是需要进行动态调整的,做起来好像就不是那么方便了,通常情况下,asp.net ...

  2. 史上最全单链表的增删改查反转等操作汇总以及5种排序算法(C语言)

    目录 1.准备工作 2.创建链表 3.打印链表 4.在元素后面插入元素 5.在元素前面增加元素 6.删除链表元素,要注意删除链表尾还是链表头 7.根据传入的数值查询链表 8.修改链表元素 9.求链表长 ...

  3. 2020 .NET 开发者峰会顺利在苏州落幕,相关数据很喜人以及线上直播回看汇总

    在2019年上海中国.NET开发者大会的基础上,2020年12月19-20日 继续以"开源.共享.创新" 为主题的第二届中国 .NET 开发者峰会(.NET Conf China ...

  4. 什么是Solon?

    Solon是参考Spring boot 和 Javalin 而设计.吸取了两者的的优点,避开了很多繁重的设计,使其支持http, websocket, socket 三种通讯信号接入.Solon 2M ...

  5. mysql-font1251错误

    控制台中先连接mysql: ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; ALTER US ...

  6. 第二章节 BJROBOT IMU 自动校正 【ROS全开源阿克曼转向智能网联无人驾驶车】

    1.把小车平放在地板上,用资料里的虚拟机,打开一个终端 ssh 过去主控端启动roslaunch znjrobot bringup.launch . 2.再打开一个终端,ssh 过去主控端,在 ~/c ...

  7. springboot项目父依赖管理

    springboot项目,pom文件中,要引用父pom文件,进而使用其依赖关系 例如: <parent> <groupId>org.springframework.boot&l ...

  8. Beta冲刺——第十天(补发)

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE1 这个作业要求在哪里 https://edu.cnblogs.com/campus/fz ...

  9. Logstash学习之路(四)使用Logstash将mysql数据导入elasticsearch(单表同步、多表同步、全量同步、增量同步)

    一.使用Logstash将mysql数据导入elasticsearch 1.在mysql中准备数据: mysql> show tables; +----------------+ | Table ...

  10. [ABP教程]第三章 创建、更新和删除图书

    Web应用程序开发教程 - 第三章: 创建,更新和删除图书 关于本教程 在本系列教程中, 你将构建一个名为 Acme.BookStore 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以 ...