• EnvironmentPostProcessor怎么做单元测试?阿里P7解答


    简介

    从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必读技术书籍

    作者:万猫学社
    出处:http://www.cnblogs.com/heihaozi/
    版权声明:本文遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接和本声明。
    微信扫描二维码,关注万猫学社,回复「电子书」,免费获取12本Java必读技术书籍。
  • 相关阅读:
    Android ListView嵌套Button,Button事件覆盖item事件解决办法
    android 再按一次退出程序(实现代码)
    Android 带checkbox的listView 实现多选,全选,反选
    Android调用第三方应用
    Android输入法界面管理(打开/关闭/状态获取)
    ViewPager的使用方法和实现过程
    安装pycharm 2018.3 Professional Edition
    layui和jquery冲突:Syntax error, unrecognized expression: +
    解决因为本地代码和远程代码冲突,导致git pull无法拉取远程代码的问题(转载)
    Object.assign()
  • 原文地址:https://www.cnblogs.com/heihaozi/p/14306530.html
Copyright © 2020-2023  润新知