Я понимаю, что управляемый bean работает как контроллер, потому что ваша единственная задача - "связать" интерфейс "Просмотр слоя с моделью".
Если я хочу вставить некоторый компонент (из Spring) в этом managedBean, у меня есть два пути:
Ответ 2
@ManagedBean
vs @Controller
Прежде всего, вы должны выбрать один фреймворк для управления вашими компонентами. Вы должны выбрать JSF или Spring (или CDI) для управления вашими компонентами. Хотя следующие работы, это в корне неправильно:
@ManagedBean // JSF-managed.
@Controller // Spring-managed.
public class BadBean {}
В итоге вы получите два совершенно разных экземпляра одного и того же класса управляемых компонентов: один управляется JSF, а другой - Spring. Непонятно, какой именно будет использоваться в EL, когда вы ссылаетесь на него как #{someBean}
. Если у вас зарегистрирован SpringBeanFacesELResolver
в 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 {}
Когда вы ссылаетесь на вышеупомянутый bean-компонент через #{someBean}
, он возвращает bean- #{someBean}
управлением Spring, а не bean- #{someBean}
областью представления под управлением JSF.
@ManagedProperty
vs @Autowired
Специфичная для JSF @ManagedProperty
работает только в управляемых JSF bean-компонентах, т.е. когда вы используете @ManagedBean
. Специфичный для Spring @Autowired
работает только в управляемых Spring bean-компонентах, т.е. когда вы используете @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
зарегистрированный в SpringBeanFacesELResolver
faces-config.xml
согласно javadoc,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
и, таким образом, вы можете ссылаться на управляемые bean-компоненты Spring в EL через #{springBeanName}
, затем вы можете просто ссылаться на них в @ManagedProperty
, так как он в основном устанавливает @ManagedProperty
результат данного выражения EL. И наоборот, внедрение управляемого компонента JSF через @Autowired
никоим образом не поддерживается. Однако вы можете использовать @Autowired
в управляемом компоненте JSF при расширении компонента из SpringBeanAutowiringSupport
. Это автоматически зарегистрирует экземпляр управляемого JSF-компонента в контексте SpringWare Spring во время вызова конструктора, что означает, что все @Autowired
будет доступно в @PostConstruct
и позже.
@ManagedBean // JSF-managed.
@ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport implements Serializable {
@Autowired
private SpringBeanClass springBeanName; // No setter required.
@PostConstruct
private void init() {
// springBeanName is now available.
}
}
Или, если ваша архитектура не позволяет расширять 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
Spring @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
компонент @Named
. С другой стороны, @ManagedProperty
не работает внутри бина @Named
.
Целью CDI является объединение всех различных структур управления компонентами в единую спецификацию/интерфейс. Spring мог бы быть полной реализацией CDI, но они решили реализовать ее только частично (поддерживается только JSR-330 javax.inject.*
, Но не JSR-299 javax.enterprise.context.*
Нет). Смотрите также Будет ли Spring поддерживать CDI? и этот урок.
JSF перейдет на CDI для управления bean- @ManagedBean
и в будущих версиях @ManagedBean
и его друзьями.
@Named // CDI-managed.
@ViewScoped // CDI-managed scope.
public class BetterBean implements Serializable {
@Inject
private SpringBeanClass springBeanName; // No setter required.
@PostConstruct
private void init() {
// springBeanName is now available.
}
}
Смотрите также: