我们的项目是单体项目,使用的是springboot的框架,随着对接的外部服务越来越多,配置文件越来越臃肿。。我们将对接的外部服务的代码单独抽离出来形成service依赖,之后以jar包的形式引入,这时候外部服务配置放到哪里算是个难题了,我主张将配置文件附着在service依赖中,这样主项目的配置文件将会非常整洁。这里举个例子,A项目是主项目,B、C两个项目分别是对接外部服务B、C的Service项目,我将对接B的配置文件放到B项目,将对接C项目的配置文件放到C项目,A直接引入B、C的依赖即可直接使用,不用在A项目中再单独配置对接B、C项目的配置了。

要想实现上面的功能,需要使用到SpringBoot的扩展点功能EnvironmentPostProcessor

一、EnvironmentPostProcessor的使用

官方文档:https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#howto.application.customize-the-environment-or-application-context

该类的作用是在SpringBoot项目启动之前自定义环境变量,可以在项目启动之前从非标准springboot配置文件中读取相关的配置并填充到springboot上下文中。

1.实现EnvironmentPostProcessor 接口

对于properties文件

public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

    @Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Resource path = new ClassPathResource("com/example/myapp/config.yml");
PropertySource<?> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
} private PropertySource<?> loadYaml(Resource path) {
Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist");
try {
return this.loader.load("custom-resource", path).get(0);
}
catch (IOException ex) {
throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
}
} }

对于yaml文件

@Slf4j
@Order
public class YamlExtPluginProcessor implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Resource path = new ClassPathResource("application-AAA.yaml");
if (!path.exists()) {
throw new IllegalArgumentException("Resource " + path + " does not exists");
}
try {
List<PropertySource<?>> load = loader.load("application-AAA", path);
log.info("发现了{}个配置文件", load.size());
for (PropertySource<?> propertySource : load) {
environment.getPropertySources().addLast(propertySource);
}
log.info("已加载 {} 配置文件", "application-AAA.yaml");
} catch (IOException e) {
throw new IllegalArgumentException("Failed to load yaml configuration from " + path, e);
}
}
}

2.在resources资源文件夹中新建META-INF/spring.factories文件

填充内容

org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor

如果只是主项目中需要配置额外的配置文件,只需要做到这里就能满足需求了,但是在我的使用场景中,并不能满足需求,我的需求是A外部依赖B、C,而这些配置要放到B、C,B和C不可运行,只是Service依赖,尽管大多数的使用都一样,但是还是有所不同。

二、外部依赖式配置

A项目resources目录

│  application-A.yaml

└─META-INF
spring.factories

B项目resources目录

│  application-B.yaml

└─META-INF
spring.factories

然后分别在A、B项目中实现EnvironmentPostProcessor接口读取相关的配置文件,并注册到spring.factories文件即可。

1.配置文件名字问题

配置文件名一定要保持唯一,这里在resources目录下新建application-xxx.properties配置文件,xxx对应着项目名,这样好记还能保持唯一性。如果配置文件名不唯一又会如何呢?如果配置文件名字都写作application-plugin.yaml,A项目有一个,B项目也有一个,则如果A项目中的先生效了,B项目中的配置文件将会被直接忽略。所以配置文件名字不能有重复的。

关于配置文件的加载先后顺序和位置问题,可以参考文档:https://blog.csdn.net/J080624/article/details/80508606

官方文档:https://docs.spring.io/spring-boot/docs/2.5.2/reference/htmlsingle/#features.external-config

2.EnvironmentPostProcessor优先级问题

官方文档中对于优先级问题有这么个提示,大意是我们读取了配置并将其放到了配置的最后,或许应当定义一个优先级以让配置在合适的情况下生效。

我的需求里,B项目和C项目的依赖中并不是放了所有的对接B、C服务的配置,而是大部分不可变的配置放到B、C,比如请求B/C服务的url;少部分不同环境不同配置的配置项放到可变的主项目的配置中,比如请求的认证信息,测试环境和生产环境不一样,那就要分别放到A项目的测试环境配置、生产环境配置文件中。

我需要B、C项目中没有但是A项目中有的配置,要全部配置一起生效;B、C项目中有的配置,A项目中也有的配置,要A项目中的生效。

B、C作为一个配角,可不能抢了主角A的戏。

解决方法就是什么都不做,或者只是加一个@Order注解到EnvironmentPostProcessor实现类上,使用默认最低的优先级;如果使用了最高的优先级,则会“喧宾夺主”,B和C项目会覆盖主项目A中的同名配置。

三、其它引入外部配置的方法

其实说起来很简单,只需要使用

spring:
profiles:
include: B,C

该配置将需要的外部配置文件引入进来即可,但是有局限性

  1. 需要外部配置文件的位置放到resources目录下并且配置文件名一定得是application-xxx.properties,符合springboot的命名规范才行,当然配置文件名字也不能一样
  2. 需要手动修改主项目A的配置,这个需要使用者反编译引入的jar包才能知道该如何做,增加了使用的复杂度

所以还是使用EnvironmentPostProcessor扩展点最好,使用者只需要引入jar包依赖,理想情况下什么都不需要配置就可以直接使用了。

巧用SpringBoot扩展点EnvironmentPostProcessor的更多相关文章

  1. SpringBoot扩展点EnvironmentPostProcessor

    一.背景 之前项目中用到了Apollo配置中心,对接Apollo配置中心后,配置中心的属性就可以在程序中使用了,那么这个是怎么实现的呢?配置中心的属性又是何时加载到程序中的呢?那么我们如果找到了这个是 ...

  2. 三万字盘点Spring/Boot的那些常用扩展点

    大家好,我是三友. Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的.本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展 ...

  3. Spring Boot 中如何使用 Dubbo Activate 扩展点

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司的核心竞争力在于创新 – <启示录> 』 继续上一篇:< Spri ...

  4. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  5. Spring扩展点-v5.3.9

    Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...

  6. Spring系列14:IoC容器的扩展点

    Spring系列14:IoC容器的扩展点 回顾 知识需要成体系地学习,本系列文章前后有关联,建议按照顺序阅读.上一篇我们详细介绍了Spring Bean的生命周期和丰富的扩展点,没有阅读的强烈建议先阅 ...

  7. Rafy 框架 - 插件级别的扩展点

    本章说明如何使用额外的插件(如客户化插件)对另一插件(如产品插件)进行扩展.   使用场景 在 产品线工程 中,项目的研发分为领域工程和应用工程.这个过程中会需要对领域工程中的内容进行大量的扩展.   ...

  8. 玩转Asp.net MVC 的八个扩展点

    MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的设计和高质量的代码也值得我们去 ...

  9. Asp.net MVC 的八个扩展点

    http://www.cnblogs.com/richieyang/p/5180939.html MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供 ...

随机推荐

  1. mysql基础之mysql主从架构

    一.概念 主从多用于网站架构,因为主从的同步机制是异步的,数据的同步有一定延迟,也就是说有可能会造成数据的丢失,但是性能比较好,因此网站大多数用的是主从架构的数据库,读写分离必须基于主从架构来搭建 二 ...

  2. linux各文件夹的作用-(转自玉米疯收)

    linux下的文件结构,看看每个文件夹都是干吗用的 /bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的 ...

  3. Oracle和MySQL差异总结

    常用功能差异 锁差异: • Oracle锁加在数据块上 • InnoDB 是在索引上加锁,所以MySQL锁的粒度没有Oracle 精细. 导入导出: • Oracle采用EXP /IMP ,EXPDP ...

  4. 常见判断错误 (Day_30)

    写给自己的话: 这是一个卡了我小半天的BUG,也是一个很低端的BUG,写篇博客吧,以后回来看看,会发现曾经的自己是如何的菜. 同样,以此记录我的进步 步入正题,这是我实现多条件分页时遇到的一个BUG, ...

  5. SqlServer事务详解(事务隔离性和隔离级别详解)

    概述 不少人对于事务的使用局限于begin transaction:开始事务.commit transaction:提交事务.rollback transaction:回滚事务的初步运用. 并且知道使 ...

  6. 为鸿蒙OS说两句公道话(我对鸿蒙OS的一些看法)

    为鸿蒙说两句公道话 今天看了鸿蒙系统的评测,看完后我感觉很欣慰,为什么这么说 ? 不是很多人吐槽鸿蒙是 Android 套壳吗 ?或者叫鸿蒙 UI 吗?说鸿蒙没有自己的核心技术.看了鸿蒙系统的设计,底 ...

  7. F5 api接口开发实战手册(二)

    F5 rest api 各对象使用方式详解 本篇文章介绍rest api接口下Collection.Resource.Subcollections.SubResource的各种使用方法.如果您不了解这 ...

  8. Yolov3 的 OneFlow 实现

    Yolov3 的 OneFlow 实现 1.简介 YOLO 系列的算法(经典的v1~v3),是单阶段目标检测网络的开山鼻祖,YOLO-You only look once,表明其单阶段的特征,正是由于 ...

  9. 重新整理 mysql 基础篇————— 介绍mysql[一]

    前言 准备整理mysql的基础篇了,前面整理了sql语句序列的的<sql 语句系列(八百章)>,感觉很多用不上,就停下来了,后续还是会继续整理. mysql 基础篇主要是对一些基础进行整理 ...

  10. 尚硅谷Java——宋红康笔记【day19-day24】

    day19 测试Thread中的常用方法: start():启动当前线程:调用当前线程的run() run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中 curr ...