Какая польза от @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.
Весь процесс выглядит так:
- Слинг создает новый экземпляр вашей модели (например,
new MyModelTest()
). - Слинг вводит все зависимости, которые вы объявили (см.
@Inject
аннотация). - Слинг вызовет метод, аннотированный
@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 содержит поддержку для тестирования моделей, использующих инъекцию в полевых условиях.