Springboot Util工具类如何读取配置文件(yml properties)

前情提要

众所周知,没有Util工具类的Java程序是不完整的

这天,我们打开了一个Springboot项目,并打算加入一个通用方法(用来拼接静态资源请求路径),那就写一个Util类吧

GPT-4: 在Java中,一个典型的工具(Util)类通常包含一些静态方法,这些方法用于提供通用的、非特定于对象的功能。这些类通常被设计成不可实例化和不可继承的

typescript 复制代码
public final class Util {
    @Value("${staticServer}")
    private static String staticServer; //静态资源服务器地址
    
    // 私有构造函数,防止实例化
    private MyUtils() {
        throw new AssertionError("No MyUtils instances for you!");
    }
    
    //拼接完整静态资源URL,如 https://static.server/images/cat.jpg
    public static String getStaticResourceURI(String prefix, String filename) {
        return staticServer + prefix + '/' + encodeUri(filename);
    }
​
    public static String encodeUri(String uri) {
        return UriUtils.encode(uri, StandardCharsets.UTF_8);
    }

优雅,太优雅了

编译!

运行!

Bomb!

好的,完犊子了,你猜这怎么着,staticServer == null

可怜 弱小 又无助

这不核理,为什么会这样呢,对静态成员的注入从技术上应该是可以实现的

不过静态成员并不属于实例对象,可能与IOC容器 & 依赖注入的理念不符,所以Springboot并不直接支持

辣怎办

但是这个需求很合理好吧,在工具类中用到配置文件中的键值

Pre

不过丑话说在前头,如果要想进行依赖注入,那么Util类必须是一个Bean,因为只有Bean才能被IOC容器管理

所以,Util的构造函数不能是私有的,还真就得开放给Springboot使用

总不能又要隐私,又要躺着把钱挣了吧(哪有这好事)

所以:

kotlin 复制代码
@Component //注册为Bean
public final class Util {
    //private MyUtils() { 公开啦!哭
    //    throw new AssertionError("No MyUtils instances for you!");
    //}
}

1. 利用set方法注入

typescript 复制代码
@Component
public final class Util {
    private static String staticServer; //静态资源服务器地址
    
    @Value("${staticServer}")
    public void setStaticServer(String staticServer) { //
        Util.staticServer = staticServer;
    }
    
    public static String getStaticResourceURI(String prefix, String filename) {
        return staticServer + prefix + '/' + encodeUri(filename);
    }
    ...
    }

@Value写在非静态成员方法上,就可以正常被执行

然后在函数体里对static成员赋值,狸猫换太子

2. 利用@PostConstruct注解

typescript 复制代码
@Component
public final class Util {
    @Value("${staticServer}")
    private String staticServer;
    private static Util INS;
​
    @PostConstruct // 在构造函数和依赖注入完成后执行;构造方法 > @Autowired > @PostConstruct,毕竟构造完成才能注入成员
    public void init() {
        INS = this; // 获取Bean实例,赋值给静态变量,方便static函数访问
    } // 容器管理的Bean默认是单例的,所以这里的INS是唯一的
​
    // 拼接完整静态资源URL,只对filename进行编码
    public static String getStaticResourceURI(String prefix, String filename) {
        return INS.staticServer + prefix + '/' + encodeUri(filename);
    }
​
    // 对uri进行编码,注意'/'也会被编码
    public static String encodeUri(String uri) {
        return UriUtils.encode(uri, StandardCharsets.UTF_8); //URLEncoder会把' '编码为'+'而非'%20'造成错误
    }
}

看到这个名字(@PostConstruct),不知道大家有没有想起什么

二叉树的后序遍历:PostOrder

诶,为什么都是Post,马萨卡

对喽,PostConstruct是在构造函数之后执行的,核理

由于执行顺序是:构造方法 > @Autowired > @PostConstruct

所以,执行@PostConstruct的时候,staticSever已经注入完成,不用担心,一切就绪

我们只要把IOC容器中的Util实例的this指针赋值给static变量INS即可(指针的赋值啊,问题不大)

什么,你问我哪来的this

你加了@Component注册为了Bean,IOC容器默认会构造单例对象的
什么,你问我Util开放了构造函数有多个实例怎么办?

@Component默认是单例的,问题不大,只要你不要自己构造一个出来
什么,你问我要是同事构造了Util怎么办?

砍了ta

问题不大,本来也没存什么状态

3. @ConfigurationProperties

typescript 复制代码
@Component
@ConfigurationProperties
public final class Util {
    private static String staticServer;
​
    public void setStaticServer(String staticServer) {
        Util.staticServer = staticServer;
    }
}

这个其实本质上也是利用set方法进行注入的,所以并不违反规则

好的好的,下班

Peace

Ref

springboot注入静态变量的两种方式_springboot 注入静态变量-CSDN博客

SpringBoot中静态变量注入方案,一网打尽-腾讯云开发者社区-腾讯云 (tencent.com)

@ConfigurationProperties与静态加载配置文件 - 简书 (jianshu.com)

相关推荐
HanhahnaH9 分钟前
Spring集合注入Bean
java·spring
未定义.22115 分钟前
电子削铅笔刀顺序图详解:从UML设计到PlantUML实现
java·软件工程·uml
雾月5532 分钟前
LeetCode 1292 元素和小于等于阈值的正方形的最大边长
java·数据结构·算法·leetcode·职场和发展
丘山子43 分钟前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
CopyLower1 小时前
在 Spring Boot 中实现 WebSockets
spring boot·后端·iphone
24k小善1 小时前
Flink TaskManager详解
java·大数据·flink·云计算
想不明白的过度思考者2 小时前
Java从入门到“放弃”(精通)之旅——JavaSE终篇(异常)
java·开发语言
.生产的驴2 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
猿周LV2 小时前
JMeter 安装及使用 [软件测试工具]
java·测试工具·jmeter·单元测试·压力测试
景天科技苑2 小时前
【Rust】Rust中的枚举与模式匹配,原理解析与应用实战
开发语言·后端·rust·match·enum·枚举与模式匹配·rust枚举与模式匹配