Интеграция Spring JSF: как внедрить компонент / сервис Spring в управляемый компонент JSF?
Я понимаю, что управляемый бин работает как контроллер, потому что ваша единственная задача - "связать" слой представления с моделью.
Чтобы использовать компонент в качестве управляемого компонента, я должен объявить @ManagedBean
аннотация, делая это, я могу общаться JSF с бином напрямую.
Если я хочу добавить какой-либо компонент (из Spring) в этот управляемый компонент, у меня есть два возможных пути:
Выберите свойство в ManagedBean (например, "BasicDAO dao") и объявите
@ManagedProperty(#{"basicDAO"})
над собственностью. Делая это, я делаю инъекцию"basicDAO"
из весны в ManagedBean.Объявлен @Controller в классе ManagedBean, тогда я буду иметь
@ManagedBean
а также@Controller
аннотации, все вместе. И в собственности"BasicDAO dao"
я должен использовать@Autowired
из весны.
Правильно ли мое понимание?
4 ответа
Существует еще один способ использования bean-компонентов, управляемых Spring, в bean-компонентах, управляемых JSF, просто расширяя ваш bean-компонент JSF из SpringBeanAutowiringSupport
и Spring будет обрабатывать внедрение зависимостей.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
// springBeanName is now available.
}
@ManagedBean
против @Controller
Прежде всего, вы должны выбрать один фреймворк для управления вашими компонентами. Вы должны выбрать JSF или Spring (или CDI) для управления вашими компонентами. Хотя следующие работы, это в корне неправильно:
@ManagedBean // JSF-managed.
@Controller // Spring-managed.
public class BadBean {}
В итоге вы получите два совершенно разных экземпляра одного и того же класса управляемых компонентов: один управляется JSF, а другой - Spring. Непонятно, какой из них будет использоваться в EL, когда вы ссылаетесь на него как на #{someBean}
, Если у вас есть SpringBeanFacesELResolver
зарегистрирован в faces-config.xml
тогда это будет управляемый Spring, а не JSF-управляемый. Если у вас этого нет, то это будет JSF-управляемый.
Кроме того, когда вы объявляете область действия управляемого JSF-компонента, такую как @RequestScoped
, @ViewScoped
, @SessionScoped
или же @ApplicationScoped
от javax.faces.*
пакет, он будет только признан и использован @ManagedBean
, Это не будет понято @Controller
как он ожидает свой собственный @Scope
аннотаций. По умолчанию используется синглтон (область применения), когда отсутствует.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
@Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}
Когда вы ссылаетесь на вышеупомянутый компонент через #{someBean}
, он будет возвращать bean-объект с областью действия под управлением Spring, а не bean-объект с областью видимости под управлением JSF.
@ManagedProperty
против @Autowired
JSF-специфичный @ManagedProperty
работает только в JSF-управляемых компонентах, т.е. когда вы используете @ManagedBean
, Весенний @Autowired
работает только в бинах, управляемых Spring, т.е. когда вы используете @Controller
, Ниже подходы являются менее или более эквивалентными и не могут быть смешаны:
@ManagedBean // JSF-managed.
@RequestScoped // JSF-managed scope.
public class GoodBean {
@ManagedProperty("#{springBeanName}")
private SpringBeanClass springBeanName; // Setter required.
}
@Component // Spring-managed.
@Scope("request") // Spring-managed scope.
public class GoodBean {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
}
Обратите внимание, что когда у вас есть SpringBeanFacesELResolver
зарегистрирован в faces-config.xml
в соответствии с Javadoc,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
и, таким образом, вы можете ссылаться на управляемые бины Spring в EL через #{springBeanName}
тогда вы можете просто сослаться на них в @ManagedProperty
также, поскольку он в основном устанавливает оценочный результат данного выражения EL. И наоборот, вводя управляемый компонент JSF через @Autowired
, никоим образом не поддерживается. Однако вы можете использовать @Autowired
в управляемом bean-компоненте JSF при ручной регистрации экземпляра управляемого bean-компонента JSF в контексте автоматической загрузки Spring, как показано ниже. Смотрите также Как правильно интегрировать JSF 2 и Spring 3 (или Spring 4).
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
@PostConstruct
private void init() {
FacesContextUtils
.getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
.getAutowireCapableBeanFactory().autowireBean(this);
// springBeanName is now available.
}
}
@XxxScoped
против @Scope
Спринга @Scope
имеет ограниченную поддержку областей JSF. Там нет эквивалента для JSF @ViewScoped
, По сути, вы либо создаете свои собственные области видимости, либо используете ручную регистрацию экземпляра управляемого JSF-компонента в контексте автопредставления Spring, как показано выше.
И, с другой стороны, Spring WebFlow был перенят в JSF 2.2 через новые @FlowScoped
аннотаций. Так что, если вы уже находитесь на JSF 2.2, вам не обязательно использовать Spring WebFlow, если вы хотите только область видимости потока.
CDI - пытаясь объединить все это
Начиная с Java EE 6, CDI предлагается как стандартная альтернатива Spring DI. Имеет соответственно @Named
а также @Inject
аннотации для этого, а также собственный набор областей. Я не уверен, как он взаимодействует с Spring, так как я не использую Spring, но @Inject
работает внутри @ManagedBean
, а также @ManagedProperty
внутри @ManagedBean
может ссылаться на @Named
боб. С другой стороны, @ManagedProperty
не работает внутри @Named
боб.
Целью CDI является объединение всех различных структур управления компонентами в единую спецификацию / интерфейс. Spring мог бы быть полной реализацией CDI, но они решили реализовать ее только частично (только JSR-330 javax.inject.*
поддерживается, но JSR-299 javax.enterprise.context.*
не). Смотрите также Будет ли Spring поддерживать CDI? и этот урок.
JSF перейдет на CDI для управления компонентами и устареет @ManagedBean
и друзья в будущей версии.
Смотрите также:
Самый простой способ сделать это - через XML. я использовал @Component
в уже сделанном JSF удалось боб, но @Autowired
не сработало, потому что управляемый bean-компонент уже был в face-config.xml. Если это обязательное сохранение определения управляемого компонента вместе с его управляемым свойством в файле xml, то предлагается добавить пружинный компонент в качестве другого управляемого свойства в теге управляемого компонента. Здесь bean-компонент spring определен в spring-config.xml (может быть подключен где-нибудь поочередно). пожалуйста, обратитесь /questions/40831445/kak-autowire-v-upravlyaemyie-bobyi-jsf/40831454#40831454
отредактировано мной. Я предлагаю либо реализовать это полностью через аннотации @Managed и @Component, либо через xml для обоих.
Вы можете автоматически соединить отдельные бобы без
@Autowired
за счет использования
getBean
текущего контекста веб-приложения.
Пожалуйста, обратитесь к ответу @BalusC для получения более подробной информации. Это всего лишь небольшая модификация его примера:
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
// @Autowired // No Autowired required
private SpringBeanClass springBeanName; // No setter required.
@PostConstruct
private void init() {
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
this.springBeanName = ctx.getBean(SpringBeanClass.class);
// springBeanName is now available.
}
}