一种相对优雅的Spring下logback多profile配置解决方案

上篇文章(http://blog.csdn.net/u014527058/article/details/76682378)介绍了一种Spring下的logback多profile配置方案,但是这种方法过于粗暴,由于是直接拉取JVM参数获得当前profile的值,而在激活profile时,JVM参数却只是其中一种方式,假如profile是使用其他方法配置的,这样做就行不通了。擅长刨根问底的我自然是很不甘心,非要想办法找到完美一点的解决方案不可。经过一番大查特查之后,终于找到了解决方案。

首先依赖包自然是少不了,这里就再贴一遍吧。


清单1 build.gradle依赖包配置

//Log  
compile 'org.slf4j:slf4j-api:1.7.21'  
compile 'org.slf4j:jcl-over-slf4j:1.7.21'  
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'  
compile group: 'org.logback-extensions', name: 'logback-ext-spring', version: '0.1.4'

现在我们假定有三个环境,分别为dev(开发环境)、test(测试环境)和prod(生产环境),在src/main/resources下存在这三个logback配置文件:

  • logback.dev.xml
  • logback.test.xml
  • logback.prod.xml
配置的思路和上篇差不多,都是先通过Environment获取当前的profile,再通过profile生成对应logback配置文件的路径,然后根据路径手动指定logback所使用的配置文件。不过相比于上篇文章采用获取JVM参数的方式获取profile名称,这次我们采用Spring自带的Environment接口来获取profile。为什么说Environment能够获取Spring所使用的profile呢?我们先来看看Environment的接口定义。

清单2 Environment接口定义
package org.springframework.core.env;

public interface Environment extends PropertyResolver {

    String[] getActiveProfiles();

    String[] getDefaultProfiles();

    boolean acceptsProfiles(String... profiles);
}

可以看到,Environment提供了getActiveProfiles()和getDefaultProfiles()分别返回当前的Active Profile和Default Profile。由于Spring允许指定多个profile,所以返回类型为String数组类型。还有一个acceptsProfiles()方法,返回指定的profile是否被激活,多个profile之间为OR的关系。


此外,Environment是一个由Spring自动生成的bean,可以直接bean中通过@Autowired, @Resource等注解或者以XML的<property>元素进行注入,也可以在Spring 4的Java config类中通过传入参数的方式注入。类似于这样:

清单3 Environment在Bean中自动注入
@Autowired
private Environment environment;

清单4 Environment在Java config中自动注入
@Bean
public ExampleBean getExampleBean(Environment environment) {
      //do something
}

不难发现,这种获取profile的方式,比之从JVM参数中获取,确实要优雅得多。
另外一个要说明的是,由于这次是在Spring中获取的profile,比WebApplicationInitializer的加载要晚一些,所以在配置logback文件时,就不能在WebApplicationInitializer里面配了。而是要在Spring里面进行配置。logback-ext-spring包里面有一个LogbackConfigurer类,通过调用里面的initLogging(String location)方法(该方法是static void方法,参数是配置文件路径),手动地在Spring中指定logback所使用的配置文件。这样的话,如何手动指定配置文件路径的问题也解决了。
但是另一个问题又来了,LogbackConfigurer.initLogging(location)这个method该如何触发呢?这就需要我们想办法让Spring在创建bean容器的过程中调用它。好在我们还有MethodInvokingFactoryBean。MethodInvokingFactoryBean,顾名思义就是方法调用FactoryBean,只要在Spring中配置了MethodInvokingFactoryBean,Spring在创建bean容器的时候就可以自动调用这个FactoryBean中指定类的指定方法。具体使用方法示意如下:

清单5 MethodInvokingFactoryBean使用方法示意
@Bean
public MethodInvokingFactoryBean factoryBean() {
    MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
    factoryBean.setTargetClass(Class<?> targetClass);
    factoryBean.setTargetMethod(String targetMethod);
    factoryBean.setArguments(setArguments(Object[] arguments));
    return factoryBean;
}

profile获取、指定配置文件路径和触发问题都解决了,我们就可以优雅地在Spring中对logback进行多profile配置了。

-------------懒人分界线,不想看原理的童鞋可以直接跳到这里---------------

好了,思路和原理已经讲清楚了,现在我们假定每次只会同时指定一个profile。如果因为某些场景的确需要指定多个profile,那么在获取profile字符串这一块就需要变通一下,不过通过Environment获取profile的思路是仍然行得通的。
先上配置:

清单6 Java config配置文件
package org.fhp.logbackdemo.config;

import ch.qos.logback.ext.spring.LogbackConfigurer;
import org.fhp.logbackdemo.util.SpringProfileUtils;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;

@Configuration
@ComponentScan("org.fhp.logbackdemo")
public class SpringRootConfig {

    @Bean
    public MethodInvokingFactoryBean logbackConfigurer(Environment environment) {
        String currentProfile = SpringProfileUtils.getProfileFromEnvironment(environment);
        MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
        factoryBean.setTargetClass(LogbackConfigurer.class);
        factoryBean.setTargetMethod("initLogging");
        factoryBean.setArguments(new String[]{String.format("classpath:logback.%s.xml", currentProfile)});
        return factoryBean;
    }
}

其中,SpringProfileUtils的实现如下:

清单7 SpringProfileUtils的实现
package org.fhp.logbackdemo.util;

import org.springframework.core.env.Environment;

public class SpringProfileUtils {

    public static String getProfileFromEnvironment(Environment environment) {
        String[] profiles = environment.getActiveProfiles();
        if(null != profiles && profiles.length != 0) {
            return profiles[0];
        }

        profiles = environment.getDefaultProfiles();
        if(null != profiles && profiles.length != 0) {
            return profiles[0];
        }

        throw new IllegalStateException("Must specify a spring profile in the environment!");
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值