SpringBoot 中的那些“开关”

SpringBoot 中的那些“开关”

在之前我们就Swagger使用篇,可以了解到根据不同环境更改为不同的配置,让不同的配置逻辑生效的处理办法。其实吧,有没有觉得这东西就像是一个开关,那么SpringBoot 我们可以怎么获取当前环境(获取其他配置相同)从而进行判断做一个开关呢?今天我们就来总结下(以下列举的是常用的几种方式):

方式一:@Value 注解

代码如下(基本容器启动什么地方都可以用):

@RestController
@RequestMapping("/test")
public class TestController {

    @Value("${spring.profiles.active}")
    String active;
    
    @GetMapping("hello")
    public String sayHello(){
        return "hello, active env is: ["+active+"]";
    }
}

方式二:Spring 配置上下文

代码如下(启动时获取):

@SpringBootApplication
public class SpringStudyApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringStudyApplication.class, args);
        String active = context.getEnvironment().getProperty("spring.profiles.active");
        System.out.println(">>>>>>>>>>>>>>>>>>>>> active env is: ["+active+"]");
        // FileHelper.xmlName = active+".xml";
        // FileHelper.ReaderXml();
    }
}

题外话:现在用了springBoot 后各种简化了的配置,properties,yaml;那你还写xml 吗?

个人觉得如果配置多了,yaml 和properties 的这种配置反而有点不直观(一行就可以写清楚的,一直往下点很多个...),可能还是得用一些xml 配置;当然不用也不是不可以,比如你们用了Apollo 自动配置,那实时修改不用发包就能生效,肯定所有的配置都整成yaml 格式的要好啊!

但是xml配置我们也得知道,看如下代码读取xml 配置文件并组装成key,value使用;对应的环境配置也可以从此处读取

引入dom4j依赖:

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>

在resources下新增文件夹configuration,新增配置文件dev.xml

<?xml version = "1.0" encoding="UTF-8"?>
<system>
    <config name="env-context" explain="环境相关">
        <item name="active" value="dev" explain="dev 环境"/>
    </config>
    <config name="def-config" explain="自定义配置">
        <item name="host" value="xxx.xxx.xxx.xxx" explain="主机ip"/>
        <item name="port" value="22" explain="端口号"/>
        <item name="account" value="root" explain="账号"/>
        <item name="password" value="123456" explain="密码"/>
    </config>
</system>

添加工具读取配置文件FileHelper类:

public class FileHelper {
    public static String xmlName = "";
    public static final Map<String,String > map = new HashMap<String, String>();

    public static void ReaderXml(){
        // 创建SAXReader的对象reader
        SAXReader reader = new SAXReader();
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        String name = "";
        String key = "";
        try {
            // 通过reader对象的read方法加载configuration.xml文件,获取docuemnt对象。
            File file = new File(xmlName);
            Resource resource = new FileSystemResource(file);

            if (!resource.exists()) {
                //jar同级目录加载目录下还是找不到,那就直接用classpath下的
                resource = resourceLoader.getResource("classpath:configuration/"+xmlName);
            }
            Document document = reader.read(resource.getInputStream());
            // 通过document对象获取根节点bookstore
            Element bookStore = document.getRootElement();
            // 通过element对象的elementIterator方法获取迭代器
            Iterator it = bookStore.elementIterator();
            // 遍历迭代器
            String keyName = "name";
            String keyValue = "value";
            while (it.hasNext()) {
                Element str = (Element) it.next();
                // 获取属性名以及属性值
                List<Attribute> strAttrs = str.attributes();
                for (Attribute attr : strAttrs) {
                    if(attr.getName().equals(keyName)){
                        name = attr.getValue();
                    }
                }
                //解析子节点的信息
                Iterator itt = str.elementIterator();
                while (itt.hasNext()) {
                    Element strChild = (Element) itt.next();
                    List<Attribute> bookChildList = strChild.attributes();
                    for (Attribute attr : bookChildList) {
                        if(attr.getName().equals(keyName)){
                            key = name +"." + attr.getValue();
                        }
                        if(attr.getName().equals(keyValue)){
                            map.put(key,attr.getValue());
                        }
                    }
                }
            }
            System.out.println(">>>>>>>>>>>>>>>>读取配置文件内容如下:"+map);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 重新加载xml配置文件
     * @return
     */
    public static Map<String,String> RestReaderXml(){
        map.clear();
        ReaderXml();
        return map;
    }
}

读取配置文件内容如下:{def-config.account=root, def-config.host=xxx.xxx.xxx.xxx, def-config.password=123456, env-context.active=dev, def-config.port=22}

那么,我们就可以根据对应的key 获取对应的配置了。

方式三:自定义SpringContextUtil工具类

代码如下:

@Component
public class SpringContextUtil implements ApplicationContextAware {
 
    private static ApplicationContext context = null;
 
    /* (non Javadoc)
     * @Title: setApplicationContext
     * @Description: spring获取bean工具类
     * @param applicationContext
     * @throws BeansException
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.context = applicationContext;
    }
 
    // 传入线程中
    public static <T> T getBean(String beanName) {
        return (T) context.getBean(beanName);
    }
 
    // 国际化使用
    public static String getMessage(String key) {
        return context.getMessage(key, null, Locale.getDefault());
    }
 
    /// 获取当前环境
    public static String getActiveProfile() {
        return context.getEnvironment().getActiveProfiles()[0];
    }
}

方式四:Environment 类

代码如下(在bean中使用,例如之前Swagger 的配置,其实只要初始化配置能够读到的地方都可以这样用):

Profiles pro = Profiles.of("dev","test");
// 判断是否是对应的环境
boolean enable = env.acceptsProfiles(pro);

详见之前的博客:Swagger食用方法详解