Какая польза от @postconstructor в концепции AEM SlingModel?

Когда я могу использовать @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");
    }
}

1 ответ

Решение

В документации говорится:

Аннотация @PostConstruct может использоваться для добавления методов, которые вызываются после завершения всех инъекций:

В приведенном вами примере кода "инъекции", о которых говорится в документации, - это поля, которые вы аннотировали с помощью @Inject аннотаций.

Когда создается модель Sling, эти поля будут "введены" Sling. Это означает, что вам не нужно устанавливать эти поля самостоятельно, но Слинг позаботится об этом. Это также называется инъекцией зависимостей.

Возвращаясь к вашему вопросу: как только все эти поля были введены Слингом, метод с @PostConstruct аннотация будет называться. Обычно этот метод используется разработчиками для дальнейшей инициализации Sling Model.

Весь процесс выглядит так:

  1. Слинг создает новый экземпляр вашей модели (например, new MyModelTest()).
  2. Слинг вводит все зависимости, которые вы объявили (см. @Inject аннотация).
  3. Слинг вызовет метод, аннотированный @PostConstruct аннотаций.

@PostConstruct аннотация в основном является заменой для конструктора. Если бы вы написали конструктор для вашей модели, вы заметили бы, что при вызове конструктора все поля с @Inject аннотации еще не установлены. Если вы попытаетесь выполнить дальнейшую инициализацию с этими полями, вы получите NullPointerException,

Вот почему @PostConstruct аннотация была введена. Это позволяет вам выполнять дальнейшую инициализацию, которую вы обычно делаете в конструкторе.

Дополнительное примечание

Внедрение зависимостей в поля называется "инъекцией полей". Есть еще один способ внедрить эти зависимости через конструктор. Это называется "инъекция в конструктор".

Лично мне нравится, когда это возможно, использовать конструктор с Sling Models. Использование инжектора конструктора помогает повысить неизменность вашей модели, может помочь уменьшить состояние и улучшить тестируемость. Это то, к чему вы обычно должны стремиться в своем коде.

Ваш пример кода должен выглядеть следующим образом:

@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 а также out теперь можно установить final что увеличивает неизменность, потому что они больше не могут быть изменены.

Когда вы вводите службы и т. Д. Для дальнейшей инициализации, вы можете сохранить результат в final поле класса, а не вводить ссылку на службу как поле класса. Те ссылки - теоретически - могут указывать на несуществующий сервис (сервисы могут приходить и уходить в OSGi). Например: если у вас есть служба, которая хранит нужные вам конфигурации, вы можете просто прочитать интересующее вас значение конфигурации и затем сохранить его в поле класса.

Последнее, но не менее важное: улучшена тестируемость, поскольку теперь вы можете создавать экземпляры, просто вызывая new MyModelTest([...]) и передавая макет logger а также out (new MyModelTest(mockLogger, mockOut)). Если бы вы использовали инъекцию поля, вам бы пришлось использовать отражение, которое обычно не то, что вы хотите сделать в своем коде. Хотя нужно сказать, что проект Sling содержит поддержку для тестирования моделей, использующих инъекцию в полевых условиях.

Другие вопросы по тегам