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

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

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

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

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

  2. Объявлен @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.
    }
}
Другие вопросы по тегам