本文最后更新于:2024年1月9日 凌晨
前情提要
众所周知,没有Util
工具类的Java
程序是不完整的
这天,我们打开了一个Springboot
项目,并打算加入一个通用方法(用来拼接静态资源请求路径),那就写一个Util
类吧
GPT-4:
在Java中,一个典型的工具(Util)类通常包含一些静态方法,这些方法用于提供通用的、非特定于对象的功能。这些类通常被设计成不可实例化和不可继承的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public final class Util { @Value("${staticServer}") private static String staticServer; private MyUtils() { throw new AssertionError("No MyUtils instances for you!"); } 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
使用
总不能又要隐私,又要躺着把钱挣了吧(哪有这好事)
所以:
1 2 3 4 5 6
| @Component public final class Util { }
|
1. 利用set方法注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @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注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component public final class Util { @Value("${staticServer}") private String staticServer; private static Util INS;
@PostConstruct public void init() { INS = this; }
public static String getStaticResourceURI(String prefix, String filename) { return INS.staticServer + prefix + '/' + encodeUri(filename); }
public static String encodeUri(String uri) { return UriUtils.encode(uri, StandardCharsets.UTF_8); } }
|
看到这个名字(@PostConstruct
),不知道大家有没有想起什么
二叉树的后序遍历:PostOrder
诶,为什么都是Post
,马萨卡
对喽,PostConstruct
是在构造函数之后执行的,核理
由于执行顺序是:构造方法 > @Autowired > @PostConstruct
所以,执行@PostConstruct
的时候,staticSever
已经注入完成,不用担心,一切就绪
我们只要把IOC
容器中的Util
实例的this
指针赋值给static
变量INS
即可(指针的赋值啊,问题不大)
什么,你问我哪来的this
?
你加了@Component注册为了Bean,IOC容器默认会构造单例对象的
什么,你问我Util
开放了构造函数有多个实例怎么办?
@Component默认是单例的,问题不大,只要你不要自己构造一个出来
什么,你问我要是同事构造了Util
怎么办?
砍了ta
问题不大,本来也没存什么状态
3. @ConfigurationProperties
1 2 3 4 5 6 7 8 9
| @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)