EnvironmentPostProcessor怎么做单元测试?

发表于:2022-2-16 09:27

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:万猫学社    来源:稀土掘金

  简介
  从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 预置准备做单元测试的属性
       * @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;
      }
  }

  附:加解密工具类代码
  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;
      }
  }

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号