简介

从Spring Boot 1.3开始,我们可以在应用程序上下文刷新之前使用EnvironmentPostProcessor来自定义应用程序的EnvironmentEnvironment表示当前应用程序运行的环境,它可以统一访问各种属性源中的属性,如属性文件、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. Docker(七): 安装Loki

    洛基(Loki),是北欧神话中的恶作剧和谎言之神,亦是火神.他是巨人法布提(Farbauti)和女巨人劳菲(Laufey)的儿子,阿萨神族主神奥丁(Odin)的义兄弟,虽然他比奥丁要年轻许多.但他的个 ...

  2. JAVA基础学习1

    一.JAVA是一种具有多种功能的高级语言:1,可以用于开发web页面上的小程序,桌面上运行的应用程序: 2,用于客户端服务器资源通讯的服务器端中间件: 3,还可以用于web服务器. 二.程序设计的5个 ...

  3. 面试 04-HTTP协议

    04-HTTP协议 一面中,如果有笔试,考HTTP协议的可能性较大. #前言 一面要讲的内容: HTTP协议的主要特点 HTTP报文的组成部分 HTTP方法 get 和 post的区别 HTTP状态码 ...

  4. 精尽Spring MVC源码分析 - LocaleResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  5. 灯光设置(light)

    clc;clear all;close all; %% 台灯的设置figure('color','k')% 底座fill3([0 1 1 0],[0 0 1 1],[0 0 0 0],'b',... ...

  6. (三)、vim的移动(旋转,跳跃)

    一.以word为单位的移动 1.w 向后移动到后一个单词词头,取自"word" This is a line with example text ----->--->- ...

  7. 浅谈 WebRTC 的 Audio 在进入 Encoder 之前的处理流程

    在 WebRTC 中,Audio 数据在被送入编码器之前,有 2 大部分需要特别关注,一是数据采集,二是 Audio Processing. 作者:方来,技术专家,从事 voip 应用开发. 数据采集 ...

  8. vue+element对常用表格的简单封装

    在后台管理和中台项目中, table是使用率是特别的高的, 虽然element已经有table组件, 但是分页和其他各项操作还是要写一堆的代码, 所以就在原有的基础上做了进一步的封装 所涵盖的功能有: ...

  9. 超详细的第一个Servlet程序

    Servlet的第一个程序! 首先查看官方文档,来编写我们的第一段代码 1.先启动Tomcat,确保我们能够正常访问. 2.http://localhost:8080/examples/     查看 ...

  10. 通过`RestTemplate`上传文件(InputStreamResource详解)

    通过RestTemplate上传文件 1.上传文件File 碰到一个需求,在代码中通过HTTP方式做一个验证的请求,请求的参数包含了文件类型.想想其实很简单,直接使用定义好的MultiValueMap ...