@PostConstruct注解初探

604 阅读5分钟

背景

有一次组内在对我的代码进行CodeReview时,我写了一个定时从库中更新数据的方法,用了一个@Scheduled注解。但是组内小伙伴就说这个注解修饰的方法不能保证服务启动后就会被调用,而应该是再加一个@PostContruct注解,确保服务启动后数据就被加载好了,而同时对方法的修饰符引起了争论,因为我用了private进行修饰,有个同事说应该用public,然后大家就巴拉巴拉,争论个不休,然后我就决定初探一下@PostConstruct注解具体的用法。

    @PostConstruct
    @Scheduled(initialDelay = 30 * 1000, fixedRate = 30 * 1000)
    private void updateClientTabHome() {
    ...}

1、@PostConstruct基本概念

@PostConstruct注解大家可能都以为是Spring框架提供时,实则是由java jdk提供的注解。

Java EE 5 引入@PostContruct和@PreDestroy注解,作用于Servlet的生命周期,实现Bean初始化之前和销毁之前的自定义操作。

该注解用于标记在依赖注入完成后需要执行的方法。通常用于执行一些初始化操作,比如启动一个后台线程或者从文件中加载数据。作用在构造函数调用之后、第一次业务方法调用之前执行。这确保了在类的任何业务方法执行之前,所需的资源已经被正确地初始化。

Contructor构造方法() -> @Autoware依赖注入 -> @PostContruct -> 类init

@PostContruct是在bean生成后执行的,通过反射方式执行,只会执行一次。这个注解主要用在基于Spring框架的应用程序中,但它也可以用在任何支持Java EE的应用服务器中。

使用PostConstruct注解的方法必须满足以下所有条件:(该方法除非是拦截器的情况,否则不得有任何参数。)

  • 在拦截器的情况下,它接受一个由拦截器规范定义的InvocationContext对象作为参数。在拦截器类上定义的方法必须具有以下签名之一:
void <METHOD>(InvocationContext)
Object <METHOD>(InvocationContext) throws Exception
PS:PostConstruct拦截器方法不得抛出应用程序异常,但如果同一个拦截器方法除了生命周期事件之外还介入业务或超时方法,它可以声明抛出包括java.lang.Exception在内的检查异常。如果PostConstruct拦截器方法返回一个值,容器将忽略它。
  • 定义在非拦截器类上的方法必须具有以下签名:
void <METHOD>()
Note:
    使用PostConstruct注解的方法可以是publicprotected、包私有或private。 
    该方法不能是静态的,应用客户端除外。 
    该方法可以是final的。 
    如果该方法抛出未检查的异常,则除非在EJB的情况下,EJB可以处理异常甚至从中恢复,否则该类不能投入使用。

@PostConstruct 注解修饰的方法通常需要遵守以下规则:

  1. 访问修饰符@PostConstruct 注解可以修饰任何访问级别的方法(public, protected, package-private, private),但是通常建议使用 public 访问修饰符,以确保容器无论在何种情况下都能调用该方法。如果使用非 public 修饰符,那么你需要确保容器能够访问该方法,这通常意味着该方法不能是 private
  2. 返回类型@PostConstruct 注解的方法必须返回 void 类型。
  3. 参数列表@PostConstruct 注解的方法不能接受任何参数。
  4. 异常声明@PostConstruct 注解的方法可以抛出运行时异常(unchecked exceptions),但是不应该声明抛出已检查的异常(checked exceptions)。
  5. 方法数量:每个类中只能有一个方法被 @PostConstruct 注解修饰。如果在类层次结构中有多个 @PostConstruct 方法,那么每个类中的方法都会被调用,子类的 @PostConstruct 方法在父类的方法之后调用。
  6. 重写@PostConstruct 注解的方法不应该被子类重写。如果子类需要自己的初始化逻辑,它应该有自己的 @PostConstruct 方法。

遵循这些规则可以确保 @PostConstruct 注解的方法能够在类实例化并注入所有依赖之后,由容器正确地调用。这些规则主要是为了确保初始化逻辑的正确执行,并避免在应用程序中引入难以发现的错误。

2、@PostConstruct如何使用

下面是一个使用 @PostConstruct 注解的例子:

import javax.annotation.PostConstruct; 

public class MyBean { 
    private String someProperty; 
    public MyBean() { 
        // 构造函数 
    } 
    @PostConstruct public void init() { 
        // 在依赖注入完成后执行初始化代码 
        someProperty = "Initialized value"; 
    } 
    // ... 其他方法 ... 
}

在上面的例子中,init 方法被标记为 @PostConstruct。当Spring框架创建 MyBean 的实例并注入所有必要的依赖之后,它会自动调用 init 方法来执行初始化代码。

需要注意的是,@PostConstruct 注解的方法只能有一个,不能接受任何参数,并且返回类型必须是 void。此外,这个方法不能抛出已检查的异常。

从 Java 9 开始,@PostConstruct 注解不再包含在 Java SE 中,而是作为 Jakarta EE 的一部分。如果你在使用 Java 9 或更高版本,并且想要使用 @PostConstruct 注解,你需要添加 Jakarta EE 或者相应的依赖库到你的项目中。在Spring框架中,@PostConstruct 注解通常与 javax.annotation-api 依赖一起使用。

参考资料:

官方文档:docs.oracle.com/javase/8/do…