#java #cdi #jboss-weld
#java #cdi #jboss-weld
Вопрос:
Я новичок в CDI и хочу использовать это для приложения JSF2. Класс MyUser
является простым @Entity
компонентом, и объект создается в @PostConstruct
методе в bean:
@Stateful
@Named @javax.faces.bean.SessionScoped
public class UserBean implements Serializable
{
@Named
private MyUser user;
//setter and getter
//@PostConstruct
}
Доступ к пользователю на страницах JSF работает как по волшебству: #{user.lastName}
. Но теперь я хочу получить доступ к этому объекту из других компонентов, например, в этом @ViewScopedBean
:
@Named @javax.faces.bean.ViewScoped
public class TestBean implements Serializable
{
@Inject private MyUser user;
}
Я хочу, чтобы текущий (зарегистрированный) MyUser user
был доступен в паре других компонентов, но я не уверен, как это сделать. Просто @Inject
отредактировать это не сработало (и я почти уверен, что это было бы немного просто).
13:56:22,371 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController]
Error installing to Start: name=vfs:///Applications/Development/
jboss-6.0.0.Final/server/default/deploy/test.ear_WeldBootstrapBean state=Create:
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied
dependencies for type [MyUser] with qualifiers [@Default] at injection
point [[field] @Inject private test.controller.mbean.TestBean.user]
Каков наилучший подход для доступа к user
из других компонентов? Код в стиле JSF1.2, подобный UserBean bean = (UserBean)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("UserBean");
, кажется, кажется старомодным!
Ответ №1:
Прежде всего: Вы не хотите напрямую внедрять объекты. Объекты довольно независимо управляются ORM-фреймворком и имеют свой собственный жизненный цикл. Не используйте их как управляемые компоненты.
Согласно этому определению, объекты JPA являются технически управляемыми bean-компонентами. Однако объекты имеют свой собственный особый жизненный цикл, состояние и модель идентификации и обычно создаются с помощью JPA или с использованием new. Поэтому мы не рекомендуем напрямую вводить класс entity. Мы особенно не рекомендуем назначать классу объектов область, отличную от @Dependent, поскольку JPA не может сохранять введенные прокси CDI.
Подробности смотрите здесь.
Чтобы ответить на ваш вопрос: вы не можете «извлечь» что-то вроде (аутентифицированного) пользователя, даже если это было возможно в Seam 2, весь механизм прокси CDI больше этого не допускает. Что вам нужно сделать, так это следующее:
- Напишите управляемый компонент, который обрабатывает аутентификацию, и поместите его в правильную область (возможно, область сеанса).
- Если вход в систему выполнен успешно, используйте атрибут этого компонента для сохранения аутентифицированного пользователя.
- Используйте метод производителя (возможно, с таким определителем, как
@LoggedIn
), чтобы сделать пользователя доступным в вашем приложении
Внедрить пользователя следующим образом:
@Inject
@LoggedIn
private User user
Это способ CDI 😉
Комментарии:
1. Спасибо за этот ответ, помогающий мне понять CDI. С помощью предоставленных вами ключей я также нашел это oracle.com/technetwork/articles/javaee /… и это работает как в вашем примере. Единственное, что мне интересно, это
@LoggedIn
аннотация. Это не может быть разрешено здесь!@Poduces
разрешается вjavax.enterprise.inject.Produces
.2. @LoggedIn — это квалификатор — ваша собственная аннотация :-). Вот как работает защита типов в CDI: всякий раз, когда существует более одного компонента определенного типа (скажем, User), вам нужно сообщить контейнеру, какого пользователя вы хотите внедрить — и это достигается с помощью квалификаторов. Смотрите здесь для получения более подробной информации: docs.jboss.org/weld/reference/latest/en-US/html /…
Ответ №2:
Является ли компонент @Inject ed также компонентом @Named?
Если это так, имеет ли компонент MyUser меньшую область видимости, чем testBean. Помните, что управляемыми свойствами компонента @ViewScoped bean должны быть @ViewScoped, @SessionScoped или @ApplicationScoped
Комментарии:
1. Да, смотрите код. Оба компонента являются
@Named
. Я хочу получить доступ к свойству@SessionScoped
компонента из@ViewScoped
компонента.2. Вы правы с чистым JSF, вы должны позаботиться об этом вопросе. Если вы используете CDI и, например, MyFaces CODI, вам больше не нужно заботиться об этом.
Ответ №3:
CDI не определяет @ViewScoped
аннотацию. Это аннотация JSF2. Единственными разрешенными аннотациями являются: @RequestScoped
, @SessionScoped
, @ApplicationScoped
@Dependent
и @ConversationScoped
. Первые три являются единственными областями JSF, разрешенными CDI.
Если вам нужно поддерживать @ViewScope
аннотацию, вам нужно будет написать ее самостоятельно. К счастью, кто-то другой делал это раньше.
Комментарии:
1. Обе области импортируются из пакета
javax.faces.bean
(приведенный выше код обновлен) К счастью, модуль SeamFaces доступен, и я попытаюсь его использовать. Мне все еще интересно, разрешен ли в этом случае подход к@Inject
свойству в другом компоненте.2. Ну, по крайней мере, доступны seam-faces, потому что у меня есть зависимость maven для этого…
3. Как MyFaces CODI, так и SeamFaces преобразуют аннотацию ViewScoped в область CDI. Позаботьтесь о том, какой из них вы используете прямо сейчас, потому что конвертер SeamFaces поврежден с помощью Weld ( issues.jboss.org/browse/SEAMFACES-44 )