您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

时间:2019-10-10 10:26:13  来源:  作者:

前言

关于nacos客户端如何获取到服务端的配置信息的主流程源码分析和客户端拉取服务端变更的主流程源码分析在前两篇文章都分析过了,虽然读的人并不是很多,加起来也没有200个人阅读,也不知道是我写的不好,还是大家对nacos的源码并不感兴趣,不过既然是系列教程,我们还是要坚持把这个小系列教程做完,本小节本来要介绍nacos和spring boot整合的主流程源码分析的,但是思来想去,还是先花几个小节把spring boot的启动流程中涉及到的主要组件一起学习一下,这样可能分析nacos和spring boot整合时候,大家理解的可能会快一点,达到事半功倍的效果

本文为原创文章,主要讲解spring boot一个核心组件EnvironmentPostProcessor,阅读本文大约7分钟,如果觉得本文写的不错,请给一个点赞或者关注一下,您的支持是我写作的最大动力

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

EnvironmentPostProcessor功能说明

EnvironmentPostProcessor从名字上看,叫做"环境后置处理器",它是一个接口,它可以再spring上下文启动的时候,去初始化一些基本配置信息,将某些变量信息,加载到spring容器上下文中,更加通俗的理解就是它可以用来解析加载我们自定义额外properties

举例来说:

1) 我们可以使用EnvironmentPostProcessor来加载json文件中的kv属性,将其解析到全局的环境变量里面,然后使用@Value来获取到信息

2)我们甚至可以使用EnvironmentPostProcessor来加载远程的配置,例如我们可以使用这个组件加载nacos的服务器的配置信息

EnvironmentPostProcessor 实战——加载本地json数据

step1.编写测试数据

1.1.首先在spring boot的hello world项目的resource文件夹下新建一个测试的json——custom_properties文件,就写两个简单的kv值

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

1.2.存在的位置在resources/json/custom_properties.json,格式如下

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

step2.自定义EnvironmentPostProcessor

2.1.新建BazingaJsonEnvironmentPostProcessor,这个类主要是读取我们刚才写的cutom_properties.json的文本信息,然后加载到spring的Environment中,BazingaJsonEnvironmentPostProcessor继承我们今天的主角EnvironmentPostProcessor,这是一个接口,我们需要实现postProcessorEnvironment接口

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

这个接口就是首先读取cutom_properties.json转换成流,然后将流读取成kv值,变成properties,最后写入到ConfigurableEnvironment中去,这样当spring的context开始初始化的时候,就能够在ConfigurableEnvironment中读取到变量,主要实现代码如下

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

核心实现逻辑

2.2 我们有了自定义的BazingaJsonEnvironmentPostProcessor之后,还是不够的,还缺一个驱动力,springboot启动的时候,不会去主动读取我们自定义的类的,所以我们还需要利用spring boot的SPI机制,来加载我们的环境后置处理器,我们再resources下新建一个文件夹META-INF,然后在META-INF下新建文件spring.factories,整体结构如下图所示

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

spring.factories

2.3 文件的内容也是有规范的,我们要指定spring的接口具体的实现类是我们自定义的

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

到这边为止,我们所有的配置就到此结束了,最后我们写一个简单的测试controller,来测试一下我们自定义的两个KV能否在@Value这种注解中生效

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

我们整体的项目骨架图如下图所示

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

我们简单地运行一下localhost:8080/json/hello,可以在浏览器中成功展示我们的"您好,世界",这样我们就可以成功地将我们自定义的文件中的属性值,让spring boot加载到,并成功运用到我们真实的项目中去了,虽然很简单,但是这个组件EnvironmentPostProcessor的使用套路,大家还是要掌握的,很多优秀的源代码中都运用了这个套路,例如携程的Apollo.

EnvironmentPostProcessor的原理讲解

我们已经初步懂得了EnvironmentPostProcessor的使用技巧,还有它的作用,在讲解原理之前,我们首先要记得一点,如果你有特殊的配置文件要加载的话,使用EnvironmentPostProcessor是很方便的,因为spring boot加载它的顺序是所有组件中最靠前的,等下我们分析看源码的时候,就能体会到这点了

这个源码分析也很简单,debug走一遍源码5分钟也就到了我们今天说的这个组件了,入口当然是我们的main函数了,我们只要看SpringApplication的源码基本上就了解了

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

我们先打开SpringApplication#run方法

step1:我们第一个要关注的就是spring boot首先初始化了一个全局的事件监听器,这个事件监听器会伴随着springboot的整个生命周期,这个我们以后也会多次接触这个组件

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

初始化全局的事件监听器EventPublishingRunListener

step2:接下来就是开始准备springboot所有配置文件存储的仓库Environment,这个其实也很好理解,spring是管理bean的,bean里面也有很多属性,所以优先收集整个上下文的配置属性信息,将其放在一个篮子(Environment)里面,然后以后想要什么,就从篮子里面去获取,而不是在想要的时候,在去想办法获取,这样会导致整个springboot的代码变得不是很优雅

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

step3:我们进入prepareEnvironment方法

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

我们可以看到首先先调用getOrCreateEnvironment创建好一个"篮子",有了这个"篮子"我们才可以在这个"篮子"里面放我们想要的东西,所以我们可以接着看下一行的#configureEnvironment方法,例如System.setProperties之类信息会在这边进行加载,放到篮子里面

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

主要是加载如下的配置文件,你不要小看这样的配置文件,运维很有用,运维启动启动一般会配置启动参数,其实也就是在这个地方,启动参数被会spring boot解析到作为默认选项,加载到上下文中,作为启动的核心参数启动,但是一般这些参数叫做默认参数,优先级是最低的,如果你在代码有同key值的时候,就会覆盖运维配置的系统级变量值,这点我们平时开发的时候要注意,如下图所示,这点很重要,不过不是我们今天的重点

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

其实就算大家不看spring的源码,但是也知道spring有一个很牛的源码原则就是"开闭原则","篮子"是spring自己造的,东西也是spring自己放的,不能让我们这些使用者没有一点机会去做点什么,肯定不是springboot的风格,所以spring就开了一个口子,简单地说就是开了一个后门,貌似在说:我东西放完了,你有什么东西要放的啊,口子就在如下的代码中

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

我们可以看到方法名叫做environmentPrepared,调用者是listener,是一个监听器,也就是我们上文说的EventPublishingRunListener监听器,就是像是在说:"同志们,篮子我已经弄好了,你们有啥东西想放的赶紧放,放完我准备开始用了"

最后我们跟着源码debug,会到了ConfigFileApplicationListener的监听器实例,它监听的是一个ApplicationEnvironmentPreparedEvent,故其名曰"应用环境准备好事件",虽然有点绕口,也不通顺,但是看到这边我们就动了,springboot是靠一种事件订阅的方式来做解耦合的,源码如下

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

ConfigFileApplicationListener.JAVA

debug到现在,我们进入onApplicationEnvironmentPreparedEvent这个方法,就可以看到我们今天的主角的影子了,有请我们的主角登场

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

EnvironmentPostProcessor初次出现

我们可以看到当loadPostProcessors执行完之后,看方法名我们也是是加载当前项目中EnvironmentPostProcessor,然后排序,最后调用我们刚刚说的postProcessorEnvironment方法,这个方法的具体实现,也就是我们上文实战小节的那个BazingaJSONEnvironmentPostProcessor的具体实践了,到现在为止,我们已经跟踪源码知道整个加载的主流程了

现在还剩下最后一个问题,为啥我们要写META-INF的spring.factorie配置文件了,答案就是在loadPostProcessors中了,这个方法是一个静态方法,调用SpringFactoriesLoader的loadFactories方法

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

 

这个SpringFactoriesLoader就有一个类似的SPI机制,会去加载META-INF下定义的类,因为这边源码比较长,但是并不是很难理解,我就贴下一个全局的类加载路径,大家基本上看一下也就能懂~

10分钟搞懂SpringBoot的组件EnvironmentPostProcessor使用和原理

SPI的类加载路径

好了,到此为止,整个分析也就结束了,基本上还是很简单的

小结

本小节其实是为了简介nacos整个spring boot源码讲解的一个铺垫,但是单独使用一个小节,也是合理的,EnvironmentPostProcessor组件在整个spring boot的生态中还是比较重要的,如果吧spring boot最后运行成功,比如一个机器人,那么EnvironmentPostProcessor组件就是开始组装这个机器人之前存放零件的仓库,以后缺什么组件都可以在这个容器中寻找~



Tags:SpringBoot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  Tags: SpringBoot  点击:(21)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  Tags: SpringBoot  点击:(25)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  Tags: SpringBoot  点击:(56)  评论:(0)  加入收藏
1. 介绍1.1 介绍今天开始我们来学习Java操作MySQL数据库的技巧,Java操作MySQL是借助JdbcTemplate这个对象来实现的。JdbcTemplate是一个多数据库集中解决方案,而我们今天只讲...【详细内容】
2021-11-05  Tags: SpringBoot  点击:(30)  评论:(0)  加入收藏
SpringBoot中的Controller注册本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMapping中。请求来了之后,web容器是如何根据请求路径找到对...【详细内容】
2021-11-04  Tags: SpringBoot  点击:(53)  评论:(0)  加入收藏
环境:Springboot2.4.11环境配置接下来的演示都是基于如下接口进行。@RestController@RequestMapping("/exceptions")public class ExceptionsController { @GetMapping(...【详细内容】
2021-10-11  Tags: SpringBoot  点击:(41)  评论:(0)  加入收藏
SpringBoot项目默认使用logback, 已经内置了 logback 的相关jar包,会从resource包下查找logback.xml, logback 文件格式范本 可直接复制使用,有控制台 info.log error.log三个...【详细内容】
2021-10-09  Tags: SpringBoot  点击:(50)  评论:(0)  加入收藏
环境:Springboot2.4.10当应用程序启动时,Spring Boot将自动从以下位置查找并加载application.properties和application.yaml文件: 从Classpath类路径classpath的根类路径classp...【详细内容】
2021-09-26  Tags: SpringBoot  点击:(78)  评论:(0)  加入收藏
搭建基础1. Intellij IDEA 2. jdk1.8 3. maven3.6.3搭建方式(1)在线创建项目Spring Boot 官方提供的一种创建方式,在浏览器中访问如下网址: https://start.spring.io/在打开的页...【详细内容】
2021-09-14  Tags: SpringBoot  点击:(78)  评论:(0)  加入收藏
最近开发项目的时候需要用到对象的属性拷贝,以前也有用过一些复制框架,比如spring的 BeanUtils.copyProperties等方式,但总是不尽如人意,最近发现使用orika进行对象拷贝挺好用的...【详细内容】
2021-08-27  Tags: SpringBoot  点击:(232)  评论:(0)  加入收藏
▌简易百科推荐
面向对象的特征之一封装 面向对象的特征之二继承 方法重写(override/overWrite) 方法的重载(overload)和重写(override)的区别: 面向对象特征之三:多态 Instanceof关键字...【详细内容】
2021-12-28  顶顶架构师    Tags:面向对象   点击:(2)  评论:(0)  加入收藏
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(12)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(13)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(11)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(11)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(17)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(19)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(22)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条