EnvironmentPostProcessor自定义配置

我们想着这块把spring相关的有用的接口都过一下,相当于二次消化吧。其实仔细反思我们这一路的学习,我们发现java这块还是有很多要学的,就日常开发的spring来说,就咋写的那些笔记呀,只是毛毛雨。而spring也仅仅是开发的一部分,你想想还有各种中间件技术,是不是感觉头都要大了,没有一定的深度的学习,恐怕很难有质的改变吧。

这块我们学习一下接口EnvironmentPostProcessor,这块我们可以理解为环境变量的处理器。那么这个接口我们在项目中应该如何使用呐?首先我们需要明白的是一个接口的使用必然要涉及其入参和返回值。一般来说java都是引用传值,因此spring的接口都是void的。这样呐,我们就更注重对入参的修改。在解决了功能性质的思考之后呐,我们想着如何让spring识别我们这样一个自定义类。一般来说对于一般的bean,可以通过注解来搞定,为啥是注解呐?因为spring在实例化之前对进行类级别注解的扫描,在最后才进行实例化的。显然如果我们的这里的EnvironmentPostProcessor接口肯定是在其他bean实例化之前实例化的,故此呐,也就只有一种姿势了,那就是spring.factories文件了。基于上述的理解呐,我们写一个demo吧!

//自定义一个配置处理器
public class MyProcessEnvironment implements EnvironmentPostProcessor {




    /**
     * 因为java是引用传值,因此我们这里可以对配置类进行各种定制化操作,除此之外,我们可以懂启动类application的参数进行修改
     * @param environment 配置类
     * @param application 启动类
     */
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        System.out.println("配置处理...");
        System.out.println("现有的配置"+environment.toString());




        //添加一个配置
        Properties properties=new Properties();
        properties.put("tian","tianjingle");
        properties.put("server.port","9999");
        PropertiesPropertySource propertiesPropertySource=new PropertiesPropertySource("a",properties);
        environment.getPropertySources().addLast(propertiesPropertySource);
        //设置spring使用a的配置
        environment.setActiveProfiles("a");
        System.out.println(application.toString());
        
        
        //修改application的对象
        //直接修改
        application.setBannerMode(Banner.Mode.OFF);
    }
}

按照上边的理解,我们在项目中创建spring.factories文件,并指定我们的EnvironmentPostProcessor

org.springframework.boot.env.EnvironmentPostProcessor=\
  com.example.demo.MyProcessEnvironment

通过上述改造,我们就可以自己定义配置文件了,不仅如此,我们还可以在spring启动之前对springapplication的属性进行直接改变。

知道怎么干很简单,我们要知道为什么,这也是咋写文章的原因。挖掘深刻的背后是我们应该干的事。所以我们debug源码看看。这块我们大概的讲解一下源码,因为全量的话太多了。

如图所示的黄色标记为我们重点要看的代码,作者通过debug发现,spring的配置处理器方法的执行是由springapplication监听器触发的,之前分析说springapplicationlistener伴随着springapplication的生命周期。

在获取springapplication监听器的时候
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class[] types = new Class[]{SpringApplication.class, String[].class};
//注意这里的getSpringFactoriesInstances方法,该方法就是从spring.factories文件中读取SpringApplicationRunListener.class对应的类,也就是等号之后的类。获取之后肯定是需要实例化的,但是实例化的过程需要参数,注意这里传入了this,也就是监听器中包含了springApplication这个类
        return new SpringApplicationRunListeners(logger,
this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
    }

通过上述获取springApplicationRunListenner的方法之后,spring运行监听器就加载好了。加载好listenners之后,springApplication逐个走starting方法。之后就开始执行我们标记的2方法。

//这里逐个监听器的执行environmentPrepared方法。   

void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        this.doWithListeners("spring.boot.application.environment-prepared", (listener) -> {
            listener.environmentPrepared(bootstrapContext, environment);
        });
    }

    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
//广播ApplicationEnvironmentPreparedEvent
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
    }

注意这里的事件为ApplicationEnvironmentPreparedEvent,我们继续跟踪。

//处理配置的事件   
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        SpringApplication application = event.getSpringApplication();
//获取配置处理器,也就是我们自定义的配置处理器
        Iterator var4 = this.getEnvironmentPostProcessors(event.getBootstrapContext()).iterator();




        while(var4.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();
            postProcessor.postProcessEnvironment(environment, application);
        }




    }

这块我们的问题是我们的processenviromment何时初始化的,作者不断的debug,终于找到了两。

我们万万没想到的是这块使用的是EnvironmentPostProcessorApplicationListener,它本质上是一个监听器,所以在处理广播事件的时候,它是会接受消息的。

我们看一下这个监听器的初始化方法。

 public EnvironmentPostProcessorApplicationListener() {
        this(EnvironmentPostProcessorsFactory.fromSpringFactories(EnvironmentPostProcessorApplicationListener.class.getClassLoader()));
    }
//实例化一个配置处理器的工厂,这个工厂的处理器均来自spring.factories文件。
    static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
        return new ReflectionEnvironmentPostProcessorsFactory(SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
    }

所以在接受到消息的时候,配置的工厂将所有的配置后置处理器返回来。然后逐个去执行。

而在消费消息的时候,也做了判断,如下所示:

 public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
        }
        if (event instanceof ApplicationPreparedEvent) {
            this.onApplicationPreparedEvent();
        }
        if (event instanceof ApplicationFailedEvent) {
            this.onApplicationFailedEvent();
        }
    }

小节:springapplicaton启动的时候将各种listener实例化并保存,配置监听器的实例化的同时通过读取spring.factories文件加载我们的配置处理器。在springboot对配置信息进行处理调用时候,通过springboot监听器进行广播,我们的EnvironmentPostProcessorApplicationListener监听到消息之后,进行判断,然后通过配置后置处理器工厂获取所有的配置后置处理器,然后逐个去调用,然后对配置和springapplication启动类的属性进行修改。

今天学的有点猛了~都凌晨了~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值