不调用抽象祖先的@PostConstruct

@PostConstruct of abstract ancestors are not invoked

我正在编写 JAX-RS 库(不是应用程序)。

我有:

abstract class A {

    @PostConstruct
    private void constructed_a() {} // not invoked

    @Inject
    private Some some;
}


public abstract class B extends A {

    @PostConstruct
    private void constructed_b() {} // not invoked
}

并测试class:

@Path("c")
public class C extends B {

    @PostConstrct
    private void constructed_c() {} // invoked
}

我正在使用 Jersey 测试框架 v2.17 进行测试

我发现只调用了constructed_c(),并没有调用祖先中定义的那些方法。请注意,在 class A 中使用 @Inject 声明的字段 (some) 已正确注入。

这正常吗?我该怎么办?


结论

我使用 embedded-glassfish 进行了测试,发现正如 Antonin Stefanutti 指出的那样,这些回调方法按预期顺序调用。

constructed_a()
constructed_b()
constructed_c()

注释不被继承。您必须为每个子 class.

创建一个 @PostConstruct 注释方法

对于 assist/remind 开发人员,您可能需要一个 postConstruct() 方法,并希望开发人员按照其名称的建议对其进行适当注释:

public abstract class A {

    @PostConstruct // annotation here has no value except as a reminder
    public abstract void postConstruct();  

根据 JSR 318 - Interceptors 1.2 规范的 在目标 Class 上声明的拦截器的调用顺序部分:

Interceptor methods declared on the target class or its superclasses are invoked in the following order:

  • If a target class has superclasses, any interceptor methods defined on those superclasses are invoked, most general superclass first.
  • The interceptor method, if any, on the target class itself is invoked.

If an interceptor method is overridden by another method (regardless of whether that method is itself an interceptor method), it will not be invoked.

这意味着在编写库/框架时,可以在父 class 和子 class 中使用 @PostConstruct 生命周期回调来实现可扩展性。

该机制在 Camel CDI 扩展中使用,它在 https://github.com/astefanutti/camel-cdi/blob/b6f52d91b247e36eefb6f3ecde61016d681d3535/impl/src/main/java/org/apache/camel/cdi/CdiCamelContext.java#L37

中声明了一个带有 @PostConstruct 生命周期回调的默认 Camel 上下文

并且可以由用户扩展,例如 https://github.com/astefanutti/camel-cdi/blob/b6f52d91b247e36eefb6f3ecde61016d681d3535/envs/se/src/main/java/org/apache/camel/cdi/se/bean/CustomLifecycleCamelContext.java#L37 声明其自己的 @PostConstruct 生命周期回调。

容器按照指定顺序调用两者。

这意味着从设计的角度来看,您的方法是正确的。但是,由于 Jersey 依赖注入是基于 HK2 而不是 CDI,并且依赖于像 jersey-gf-cdi 这样的桥梁,因此在该级别可能存在问题。