简化配置项

一、实现方式

通过spring的environmentPostProcessor扩展点将配置文件的配置项注入到准备环境中

二、具体实现

@Order(Ordered.LOWEST_PRECEDENCE)
@Data
public class AutoconfigEnvironmentPostProcessor implements EnvironmentPostProcessor, ApplicationListener<ApplicationEvent>, Ordered {
    private static final DeferredLog log = new DeferredLog();

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        log.replayTo(AutoconfigEnvironmentPostProcessor.class);
    }

    // 要获取的资源名称
    private static final String PROPERTY_SOURCE_NAME_OA = "applicationConfig: [classpath:/application-dev.yml]";
    private static final String PROPERTY_SOURCE_NAME_PREFIX = "applicationConfig: [classpath:/application";
    private static final String PROPERTY_SOURCE_NAME_SUFIX = ".yml]";
    private static final String BOTOS_TRAP = "applicationConfig: [classpath:/bootstrap.yml]";
    private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

    //默认项目配置文件
    private static final String PROPERTY_SOURCE_NAME_DEFAULT = "applicationConfig: [classpath:/application.yml]";

    private static final String CENTER = "applicationConfig: [file:cfg/application.yml]";

    // A
    private static final String APOLLO = "ApolloBootstrapPropertySources";


    // yml资源加载器
    private static final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();


    //关键方法,重写方法将全局属性塞入容器,由于这种重写方法是最先加载的,无法通过spring容器装载配置文件值,因此需要手动比对
    //具体逻辑是先将配置文件读出来,然后将启动器中配置的默认值读出来,然后循环比对
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        try {
            PropertySource<?> propertySource = null;
            log.info("【开始接管配置项】");
            Map<String, Object> resultMap = getFieldsFromClass(new OaDefaultProperties(), "");
//            String configName = checkBootsTrap(environment);
            // 通过环境后置处理器获取加载完的环境变量(加载后处理)
            String configName = getApplicationFileName(environment);
            if (environment.getPropertySources().contains(configName)) {
               propertySource = environment.getPropertySources().get(configName);
                replaceConfigs(environment,configName,resultMap);
            } else if (environment.getPropertySources().contains(CENTER)) {
                propertySource = environment.getPropertySources().get(CENTER);
                replaceConfigs(environment,CENTER,resultMap);
            }else {
                // 初始化
                propertySource = new PropertySource(PROPERTY_SOURCE_NAME_OA, resultMap) {
                    @Override
                    public Object getProperty(String name) {
                        Map<String, Object> map = (Map<String, Object>) source;
                        return map.containsKey(name) ? map.get(name) : null;
                    }
                };
                // 资源排序优先加载
                environment.getPropertySources().addFirst(propertySource);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("【配置项处理异常=>】" + e.getMessage());
        }
    }

    /**
     * 将类的属性反射递归方法抽取出来,将properties下的写的默认配置类属性读入map中
     *
     * @param targetObj       需要解析的实体类的实例
     * @param fatherClassName 父类的名称,用来拼接层级配置
     * @return
     */
    private static Map<String, Object> getFieldsFromClass(Object targetObj, String fatherClassName) {
        Map<String, Object> resultMap = new HashMap();
        Class targetClass = targetObj.getClass();
        Field[] fields = targetClass.getDeclaredFields();
        Class[] innerClasses = targetClass.getDeclaredClasses();

        //循环将类的属性塞入结果集
        for (int i = 0; i < fields.length; i++) {
            try {
                Field field = fields[i];
                // 打开私有访问
                field.setAccessible(true);
                // 获取属性
                String name = field.getName();
                //处理特殊字符
                if (!StringUtils.isEmpty(name) && name.contains("$") ) {
                    name = name.replace("$$"," ").trim().replace("$", "-");
                }
                // 获取属性值
                Object value = field.get(targetObj);
                if (fatherClassName.equals("")) {
                    resultMap.put(name, value);
                } else {
                    if (!StringUtils.isEmpty(fatherClassName) && fatherClassName.contains("$") ) {
                        fatherClassName = fatherClassName.replace("$$"," ").trim().replace("$", "-");
                    }
                    resultMap.put(fatherClassName + "." + name, value);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                log.error("【属性反射异常,原因】" + e.getMessage());
            }
        }

        //处理类下的子类
        for (Class claszInner : innerClasses) {
            log.info("正在处理配置模块【" + claszInner.getSimpleName() + "】");
            Map<String, Object> sonclassResultMap = new HashMap();
            try {
                String fatherconfigname = "";
                if (fatherClassName.equals("")) {
                    fatherconfigname = claszInner.getSimpleName();
                } else {
                    fatherconfigname = fatherClassName + "." + claszInner.getSimpleName();
                }
                //递归将子类下的属性放入容器
                sonclassResultMap = getFieldsFromClass(claszInner.newInstance(), fatherconfigname);
                resultMap.putAll(sonclassResultMap);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("【自动配置的Properties中,内部类构造器有问题】");
            }

        }
        return resultMap;
    }

    private void replaceConfigs(ConfigurableEnvironment environment,String  cfgName,Map<String,Object>resultMap) {
        PropertySource<?> propertySource = environment.getPropertySources().get(cfgName);
        Map<String, Object> source = (Map<String, Object>) propertySource.getSource();
        for (String key : resultMap.keySet()) {
            // 循环读取到的自定义配置如果环境变量里不存在默认配置则由配置类来接管
            if (!source.containsKey(key) || source.get(key) == null || source.get(key).toString().isEmpty()) {
                log.info("已将【" + key + "】替换为【" + resultMap.get(key) + "】");
                source.put(key, resultMap.get(key));
            }
        }
    }

    private String getApplicationFileName(ConfigurableEnvironment environment){
        String name = "";
        for (PropertySource<?> propertySource : environment.getPropertySources()) {
            log.info("【获取到配置文件=>"+ propertySource.getName() +"】");
            if(propertySource.getName().indexOf(PROPERTY_SOURCE_NAME_PREFIX) >=0){
                name = propertySource.getName();
                break;
            }
        }
        return StringUtils.isEmpty(name)?PROPERTY_SOURCE_NAME_OA:name;
    }

通过反射读取配置类信息将配置加载到环境中,如果配置文件没有配置相关配置信息则自动加载配置类中的配置项,从而实现配置文件的简化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值