Spring Интеграция JSF: как внедрить компонент/службу Spring в управляемый JSF bean?

Я понимаю, что управляемый bean работает как контроллер, потому что ваша единственная задача - "связать" интерфейс "Просмотр слоя с моделью".

Чтобы использовать bean как управляемый bean, я должен объявить аннотацию @ManagedBean, делая это, я могу напрямую связывать JSF с bean.

Если я хочу вставить некоторый компонент (из Spring) в этом managedBean, у меня есть два пути:

  • Выберите свойство в ManagedBean (например, "BasicDAO dao" ) и объявите @ManagedProperty(#{"basicDAO"}) над свойством. Выполняя это, я вставляю bean "basicDAO" из Spring в ManagedBean.

  • Объявлено @Controller в классе ManagedBean, тогда у меня будут аннотации @ManagedBean и @Controller, все вместе. И в свойстве "BasicDAO dao" я должен использовать @Autowired из Spring.

Правильно ли я понимаю?

Ответ 1

Существует еще один способ использования Spring -managed beans в управляемом JSF beans путем простого расширения JSF bean от 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.
}

Ответ 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.
    }
}

Смотрите также:

Ответ 3

Легкий способ сделать это через XML. Я использовал @Component в уже выполненном jsf управляемом bean, но @Autowired не работал, потому что управляемый bean был уже там в faces-config.xml. Если необходимо сохранить это управляемое определение bean вместе с его управляемым свойством в XML файле, то предлагается добавить spring bean в качестве другого управляемого свойства внутри управляемого тега bean. Здесь spring bean определен в spring -config.xml(он может быть поочередно передан в другое место). пожалуйста, обратитесь fooobar.com/info/8925/...

отредактировал меня. Я предлагаю либо реализовать его полностью через аннотацию @Managed и @Component, либо через xml для обоих.