-3

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

@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");
    }
}
4

1 回答 1

1

文档指出:

@PostConstruct 注释可用于添加在完成所有注入时调用的方法:

在您提供的示例代码中,文档谈到的“注入”是您使用注释注释的字段@Inject

当 Sling 模型被实例化时,这些字段将被 Sling “注入”。这意味着您不必自己设置这些字段,但 Sling 会处理它。这也称为依赖注入

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

整个过程是这样的:

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

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

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

附加说明

将依赖项注入字段称为“字段注入”。还有另一种方法可以通过构造函数注入这些依赖项。这称为“构造函数注入”。

就个人而言,我喜欢尽可能将构造函数注入与 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;
    }
}

现在可以设置类字段logger和,这增加了不变性,因为它们不能再更改了。outfinal

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

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

于 2018-06-14T18:27:46.057 回答