根据请求动态设置 @Value 注入的属性值

先说一下可以使用的场景
项目中有一些功能类使用了@Value修饰, 这种属性取值通常要么是读取 yml 的配置文件,要么是读取配置中心.
在我们在本地调试的时候Controller时, 如果 如果Service层用到了 @Value修饰 的属性时, 但是需要根据这个请求去 动态去读取值 , 那么我们可以给这个请求增加一个标识 (如下面案例 请求头中加了个 env ) ,
如果请求头是 env有值,那就让这个请求去调用 uat 环境的接口 (这个可以自己配置) , 如果没值, 那就让它读取 读取 yml 的配置文件,要么或者配置中心的接口
这样,就能比较方便的,相当于不用重新运行项目也能动态修改 配置 (比较通常运行项目时,就会先指定 当前是什么环境, 然后读取什么配置 , 比如 dev 读取 dev.yml , test 读取 test.yml , 但这样配置好后,就不用这么麻烦重启项目了 )
当然,您还可以在此基础上进行优化,因为这里仅仅方便调试而已,所以就先这样咯


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.*;

@Component
@Configuration
public class EnvironmentPropertiesProcessor implements BeanPostProcessor , HandlerInterceptor, ApplicationContextAware, WebMvcConfigurer {

    private final Map<String, Map<String, Object>> envPropertiesMap = new HashMap<>();
    private final List<String> beanNameList = new ArrayList<>();

    private final  Map<String, Object> initPropertiesMap = new HashMap<>();//配置文件的值

    //调试配置
    private final static Map<String, Object> uatValueMap =  new HashMap<String, Object>(){{
        //todo 把要替换的直接粘贴到这就行了
        put("${http-request.conn-timeout:5000}","10000");
        put("${nebula.secret.key}","1234567812345678");
        put("${fund-trade.host}","sss-uat.xxx.online"););

    }};

    private static final String ENV_KEY = "env";

    private static ApplicationContext context;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        EnvironmentPropertiesProcessor bean = context.getBean(EnvironmentPropertiesProcessor.class);
        System.out.println("读取本地项目用@Value的配置文件:" + context.getBean(EnvironmentPropertiesProcessor.class).initPropertiesMap);
        System.out.println("转换后");
        for (Map.Entry<String, Object> entry : context.getBean(EnvironmentPropertiesProcessor.class).initPropertiesMap.entrySet()) {
            try {
                // 这里打印出来方便复制放到 上面粘贴 , put("xxx","xxx")
                String value = entry.getValue().toString();
                System.out.println("put(" + "\"" +  entry.getKey() + "\"," + "\"" + value.replaceAll("dev|test","uat") + "\"" + ");");
            }catch (Exception e){
                //System.out.println( "\"" +  entry.getValue()  + "\"" + entry.getValue());
            }
        }
        System.out.println();
        registry.addInterceptor(bean);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 扫描bean中带有@Value注解的属性,并将其加入到envPropertiesMap中
        Class<?> clazz = bean.getClass();
        Map<String, Object> propertiesMap = new HashMap<>();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            Value valueAnnotation = AnnotationUtils.getAnnotation(field, Value.class);
            if (valueAnnotation != null) {
                String key = valueAnnotation.value();
                ReflectionUtils.makeAccessible(field);
                Object value = ReflectionUtils.getField(field, bean);
                propertiesMap.put(key, value);
                initPropertiesMap.put(key, value);
            }
        }
        if (!propertiesMap.isEmpty()) {
            envPropertiesMap.put(beanName, propertiesMap);
            beanNameList.add(beanName);
        }
        return bean;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String env = request.getHeader(ENV_KEY);
        if (env != null && !env.isEmpty()) {
            for (String name : beanNameList) {
                Object bean = context.getBean(name);
                try {
                    Field[] fields = bean.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        // 找到需要设置的属性,并将其值注入
                        if (field.isAnnotationPresent(Value.class)) {
                            Value valueAnnotation = field.getAnnotation(Value.class);
                            String expression = valueAnnotation.value();
                            field.setAccessible(true);
                            Object uatValue = uatValueMap.get(expression);
                            if (!StringUtils.isEmpty(uatValue)) {
                            	//todo  这里还可以自己完善,但一般来说大多配置都是字符串
                                if (field.getType().getName().equals("java.lang.String")) {
                                    field.set(bean, uatValue);
                                }
                                //...
                            }
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求结束后,还原
        String env = request.getHeader(ENV_KEY);
        if (env != null && !env.isEmpty()) {
            for (String name : beanNameList) {
                Object bean = context.getBean(name);
                try {
                    Field[] fields = bean.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        // 找到需要设置的属性,并将其值注入
                        if (field.isAnnotationPresent(Value.class)) {
                            Value valueAnnotation = field.getAnnotation(Value.class);
                            String expression = valueAnnotation.value();
                            field.setAccessible(true);
                            Object str = initPropertiesMap.get(expression);
                            if (!StringUtils.isEmpty(str)) {
                                field.set(bean, str);
                            }
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值