Как заставить bean-объект в области приложения создавать экземпляры при запуске приложения? - PullRequest
36 голосов
/ 30 августа 2010

Кажется, я не могу найти способ принудительно создать экземпляр / инициализировать управляемый компонент приложения при запуске веб-приложения. Кажется, что bean-объекты области приложения лениво создаются при первом обращении к bean-компоненту, а не при запуске веб-приложения. Для моего веб-приложения это происходит, когда первый пользователь впервые открывает страницу в веб-приложении.

Причина, по которой я хочу этого избежать, заключается в том, что во время инициализации моего bean-объекта области действия приложения происходит много трудоемких операций с базой данных. Он должен извлечь кучу данных из постоянного хранилища, а затем кэшировать некоторые из них, которые будут часто отображаться пользователю в виде элементов ListItem и т. Д. Я не хочу, чтобы все это происходило, когда первый пользователь подключается и, таким образом, вызвать длительную задержку.

Моей первой мыслью было использовать метод contextInitialized () ServletContextListener старого стиля и оттуда использовать ELResolver для ручного запроса экземпляра моего управляемого компонента (таким образом, вызывая инициализацию). К сожалению, я не могу использовать ELResolver для запуска инициализации на этом этапе, поскольку для ELResolver требуется FacesContext, а FacesContext существует только в течение срока службы запроса.

Кто-нибудь знает альтернативный способ сделать это?

Я использую MyFaces 1.2 в качестве реализации JSF и в настоящее время не могу выполнить обновление до 2.x.

Ответы [ 4 ]

56 голосов
/ 30 августа 2010

Моей первой мыслью было использовать метод contextInitialized () ServletContextListener старого стиля и оттуда использовать ELResolver для ручного запроса экземпляра моего управляемого компонента (таким образом, чтобы инициализация происходила).К сожалению, я не могу использовать ELResolver для запуска инициализации на этом этапе, потому что ELResolver нужен FacesContext, а FacesContext существует только в течение срока жизни запроса.

Это не такдолжно быть , что сложно.Просто создайте экземпляр компонента и поместите его в область приложения, указав в качестве ключа то же самое имя управляемого компонента.JSF будет просто повторно использовать компонент, когда он уже присутствует в области.С JSF поверх Servlet API ServletContext представляет область приложения (так как HttpSession представляет область сеанса, а HttpServletRequest представляет область запроса, каждый с методами setAttribute() и getAttribute()).

Это должно сделать,

public void contextInitialized(ServletContextEvent event) {
    event.getServletContext().setAttribute("bean", new Bean());
}

, где "bean" должно быть таким же, как <managed-bean-name> компонента в области приложения в faces-config.xml.


Только длязапись в JSF 2.x все, что вам нужно сделать, это добавить eager=true к @ManagedBean в @ApplicationScoped bean-компоненте.

@ManagedBean(eager=true)
@ApplicationScoped
public class Bean {
    // ...
}

Затем он будет автоматически создан при запуске приложения.

Или, когда вы управляете поддержкой бинов по CDI @Named, тогда захватите OmniFaces @Eager:

@Named
@Eager
@ApplicationScoped
public class Bean {
    // ...
}
10 голосов
/ 11 сентября 2015

Ромен Манни-Букау опубликовал изящное решение для этого, которое использует CDI 1.1 в своем блоге .

Хитрость заключается в том, чтобы компонент мог наблюдать инициализацию встроенных областей жизненного цикла.в данном случае ApplicationScoped.Это также может быть использовано для очистки выключения.Итак, пример выглядит так:

@ApplicationScoped
public class ApplicationScopedStartupInitializedBean {
    public void init( @Observes @Initialized( ApplicationScoped.class ) Object init ) {
        // perform some initialization logic
    }

    public void destroy( @Observes @Destroyed( ApplicationScoped.class ) Object init ) {
        // perform some shutdown logic
    }
}
2 голосов
/ 30 августа 2010

Насколько я знаю, вы не можете принудительно создать экземпляр управляемого компонента при запуске приложения.

Возможно, вы могли бы использовать ServletContextListener, который вместо создания экземпляра управляемого компонента будет выполнять всю базу данных.сами операции?


Другим решением может быть создание экземпляра вашего компонента вручную при запуске приложения, а затем установка компонента в качестве атрибута вашего ServletContext.

Вот пример кода:

public class MyServletListener extends ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext ctx = sce.getServletContext();
        MyManagedBean myBean = new MyManagedBean();
        ctx.setAttribute("myManagedBean", myManagedBean);
    }

}

На мой взгляд, это далеко не чистый код, но кажется, что он делает свое дело.

0 голосов
/ 19 января 2016

Дополнительно к ответу BalusC выше вы можете использовать @Startup и @Singleton (CDI), например

//@Named    // javax.inject.Named:       only needed for UI publishing
//@Eager    // org.omnifaces.cdi.Eager:  seems non-standard like taken @Startup below
@Startup    // javax.ejb.Startup:        like Eager, but more standard
@Singleton  // javax.ejb.Singleton:      maybe not needed if Startup is there
//@Singleton( name = "myBean" )  //      useful for providing it with a defined name
@ApplicationScoped
public class Bean {
    // ...
}

, что хорошо объяснено здесь . Работает как минимум в JPA 2.1.

...