AEM SlingModel 概念中@postconstructor 的用途是什么?

What is the use of @postconstructor in AEM SlingModel concept?

我在 SlingModel 中使用时什么时候可以使用 @postconstructor

@Model(adaptables=SlingHttpServletRequest.class)
public class MyModelTest {

    @Inject
    private PrintWriter out;

    @Inject
    @Named("log")
    private Logger logger;

    @PostConstruct
    protected void sayHelloTest() {
        logger.info("hello world");
    }
}

documentation 状态:

The @PostConstruct annotation can be used to add methods which are invoked upon completion of all injections:

在您提供的示例代码中,文档中提到的 "injections" 是您使用 @Inject 注释进行注释的字段。

当 Sling 模型被实例化时,这些字段将由 Sling "injected"。这意味着您不必自己设置这些字段,但 Sling 会处理它。这也称为 Dependency Injection.

回到您的问题:一旦所有这些字段都被 Sling 注入,将调用带有 @PostConstruct 注释的方法。通常,开发人员使用此方法来进一步初始化 Sling 模型。

整个过程是这样的:

  1. Sling 创建模型的新实例(例如 new MyModelTest())。
  2. Sling 注入您声明的所有依赖项(参见 @Inject 注释)。
  3. Sling 将调用带有 @PostConstruct 注释的方法。

@PostConstruct 注释基本上是构造函数的替代品。如果您为模型编写构造函数,您会注意到当调用构造函数时,所有带有 @Inject 注释的字段都尚未设置。如果您尝试对这些字段进行进一步的初始化,您将得到 NullPointerException

这就是引入 @PostConstruct 注释的原因。它允许您进行通常在构造函数中进行的进一步初始化。

补充说明

将依赖项注入字段称为 "field injection"。还有另一种方法可以通过构造函数注入这些依赖项。这叫做"constructor injection".

就个人而言,我喜欢在可能的情况下对 Sling 模型使用构造函数注入。使用构造函数注入有助于提高模型的不变性,有助于减少状态并提高可测试性。这是您通常应该在代码中努力实现的目标。

您的代码示例如下所示,带有构造函数注入:

@Model(adaptables=SlingHttpServletRequest.class)
public class MyModelTest {

    private final Logger logger;
    private final PrintWriter out;

    @Inject
    public MyModelTest(
        @ScriptVariable @Named("log") final Logger logger,
        @ScriptVariable @Named("out") final PrintWriter out
    ) {
        this.logger = logger;
        this.out = out;
    }
}

现在可以设置 class 字段 loggerout final,这增加了不变性,因为它们无法再更改。

当您注入服务等以进行进一步初始化时,您也可以将结果存储在 final class 字段中,而不是将服务引用本身作为 class 字段注入.这些引用 - 理论上 - 可能指向不存在的服务(服务可以在 OSGi 中来来去去)。例如:如果您有一个存储您需要的配置的服务,您可以只读取您感兴趣的配置值,然后将其存储在 class 字段中。

最后但同样重要的是,可测试性得到改进,因为您现在可以通过简单地调用 new MyModelTest([...]) 并传递 loggerout (new MyModelTest(mockLogger, mockOut)) 的模拟来创建实例。如果您要使用字段注入,则必须使用 reflection,这通常不是您想在代码中执行的操作。虽然不得不说Sling项目包含了对使用字段注入的测试模型的支持。