@Component
public class Util {
//注入配置值
@Value("${api.server}")
private static String server;
public static void test() {
System.out.println(server);
}
}
这是一个极为简单的静态方法类,但是因为外部API服务的端口和IP不一定不变,在配置文件中给出更为方便,但是这种写法实际上跑不起来的,会出现server获取不到,无法注入
静态字段-static
-
定义:静态字段属于类,而不是某个类的实例。换句话说,无论创建多少个实例,静态字段在内存中只有一份共享的数据。
-
生命周期:静态字段在类加载时初始化,而非静态字段则在每次创建实例时初始化。
-
使用场景:静态字段通常用于保存不变的数据或者在所有实例之间共享的数据。
非静态字段
-
定义:非静态字段属于类的实例。每创建一个实例,都会有独立的一份非静态字段数据。
-
生命周期:非静态字段在实例化对象时初始化,随着实例的创建和销毁而存在。
为什么不能直接注入静态字段?
静态字段在类加载时就存在,而 Spring 的依赖注入发生在 bean 实例化之后。因为静态字段与实例无关,Spring 无法通过依赖注入机制管理静态字段的生命周期和初始化。这导致以下问题:
- 时间顺序问题:静态字段初始化发生在类加载时,而 Spring 的依赖注入发生在实例化之后。这意味着在静态字段初始化时,Spring 还没有机会注入值。
- Spring 管理范围之外:静态字段属于类本身而不是实例,Spring 管理的是 bean 实例,而不是类。因此,Spring 无法管理静态字段的依赖注入。
解决方法
使用@PostConstruct注解
@PostConstruct
是 Java EE 和 Spring 框架中的一个注解,用于标识在依赖注入完成后需要执行的方法。它通常用于在 bean 初始化后进行一些自定义初始化工作。
@PostConstruct
注解的方法会在以下事件发生后被调用:
- Bean 实例化完成。
- 所有依赖注入完成,包括字段注入和方法注入。
-
初始化方法(例如实现
InitializingBean
接口的afterPropertiesSet
方法)调用之前。典型的执行顺序
- 实例化:Spring 创建 bean 实例。
- 依赖注入:Spring 注入所有依赖的字段和方法。
- 调用
@PostConstruct
方法:执行标注了@PostConstruct
的方法进行自定义初始化。 - 初始化方法:如果实现了
InitializingBean
接口,调用其afterPropertiesSet
方法。 - Bean 可用:bean 准备好被使用。
在一些经典的场景会使用这个注解: - 初始化资源:打开文件、建立数据库连接等。
- 验证配置:检查注入的配置参数是否有效。
- 启动辅助线程或任务:在应用启动时需要执行的任务。
在这个场景中也可以这样子来实现,这样子staticServer就存在属性了// 非静态字段,用于注入配置值 @Value("${holidays.server}") private String server;
// 静态字段,用于静态方法访问
private static String staticServer;
// 初始化方法,在bean初始化时调用
@PostConstruct
public void init() {
staticServer = this.server;
}
## 使用@Autowired去调用工具类
舍弃静态,在需要用的地方去注入调用