Как программно зарегистрировать управляемый компонент JSF? - PullRequest
11 голосов
/ 19 июля 2011

Я бы хотел программно зарегистрировать / добавить класс Managed Bean (изнутри сервлета init ()) в область приложения. Как я могу сделать это с JSF 1.2?

Ответы [ 5 ]

19 голосов
/ 19 июля 2011

Маловероятно, что это можно сделать программным способом из вашего приложения для управляемых компонентов всех областей. BalusC уже указал, как это сделать для управляемых bean-компонентов в области приложения.

Рассмотрев, как управляемые bean-компоненты регистрируются в Mojarra 2.1 (реализация JSF 2.1); Существует не так много элегантных опций, доступных для программной регистрации сеанса и запроса bean-объектов в области видимости. Проще говоря, вы либо должны вызывать специфические для реализации классы, либо вам придется создавать и уничтожать, т.е. управлять компонентами самостоятельно, а не полагаться на реализацию JSF для этого.

Заполнение областей запроса и сеанса компонентами (неуправляемым способом)

Примечание. Это называется "неуправляемым способом", поскольку вы создаете компоненты, а не контейнер. Аннотации типа @PostConstruct и @PreDestroy не будут работать, если вы не обработаете их сами и не вызовете соответствующие методы. Даже внедрение зависимостей не сработает.

Выражения EL всегда оцениваются во время выполнения, так что это дает вам достаточную возможность заполнить прицел бобами перед оценкой (что позволяет выстрелить себе в ногу, если у вас есть такая возможность). В Mojarra (и, возможно, в других реализациях JSF) распознаватель EL будет использовать службы ScopeHandler (или эквивалентного класса) для разрешения значений выражения EL. Мохарра использует классы ApplicationScopeHandler, RequestScopeHandler и SessionScopeHandler для получения значений из разных областей.

Вы можете заполнить содержимое областей Сеанс и Запрос после того, как после создания нового сеанса или до обработки запроса реализацией JSF.

Заполнение области действия сеанса можно выполнить (в идеале, используя HttpSessionListener), используя:

HttpSession session = request.getSession(false);
session == null ? null : session.setAttribute("<keyname>", new Bean());

keyname должно соответствовать значениям, которые вы используете для ссылки на bean-компонент в выражениях EL.

Аналогичным образом вы можете заполнить область запроса (в идеале это делается в фильтре), используя:

ServletRequest request = ... // get the reference to the servlet request object
request.setAttribute("<keyname>", new Bean());

Если вам нужно понять, как это работает, вы должны взглянуть на классы com.sun.faces.context.SessionMap, com.sun.faces.context.RequestMap и com.sun.faces.context.ApplicationMap, чтобы увидеть, как контекстные карты управляются внутри и используются SessionScopeHandler, RequestScopeHandler и ApplicationScopeHandler классы, которые являются статическими внутренними классами класса ScopeManager (еще один статический внутренний) класса com.sun.faces.mgbean.BeanManager. Класс BeanManager - это класс, который содержит регистрацию управляемых компонентов, а в следующем разделе обсуждается, как «взломать» процесс регистрации Mojarra.

Использование классов Mojarra для регистрации бинов

Регистрация управляемых bean-компонентов в реализации Mojarra выполняется методом public void register(ManagedBeanInfo beanInfo) класса com.sun.faces.mgbean.BeanManager. Нетрудно получить доступ к классу BeanManager, используя только API-интерфейсы JSF или Servlet. Однако существует класс ApplicationAssociate Мохарры, который создает экземпляр BeanManager, и доступ к нему можно получить с помощью метода getCurrentInstance(). Другой ответ Томаса уже демонстрирует, как программно зарегистрировать управляемый компонент:

ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)

Существует оговорка с вышеуказанным подходом. Маловероятно, что этот подход будет работать в методе init Servlet по той простой причине, что метод getCurrentInstance использует переменную ThreadLocal для извлечения экземпляра ApplicationAssociate. Локальная переменная потока инициализируется классом com.sun.faces.application.WebappLifecycleListener, поэтому вы должны воспроизвести механизм, используемый классом WebappLifecycleListener, для вызова метода ApplicationAssociate getInstance(ServletContext context), чтобы получить доступ к экземпляру ApplicationAssociate. Поэтому следующий код может быть (поскольку я не пытался его использовать) лучше, если вы хотите использовать классы, специфичные для Мохарры:

ServletContext sc = ... //get the ServletContext reference;
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)

Вы все равно должны остерегаться причуд, возникающих из-за этого механизма, поскольку вполне возможно, что некоторые классы и экземпляры Mojarra не были бы загружены или инициализированы до вашего сервлета. Поэтому я бы предложил загрузку, пытаясь настроить ваш сервлет со значением load-on-startup, которое больше, чем значение, используемое FacesServlet.

13 голосов
/ 19 июля 2011

из сервлета init()

Итак, это касается запроса не-JSF.FacesContext#getCurrentInstance() вернул бы null здесь, так что он вам здесь не нужен.

Полезно знать, что управляемые bean-объекты в области JSF-приложения в основном хранятся как атрибут ServletContext.В методе init() у вас есть ServletContext в ваших руках унаследованным методом getServletContext().Итак, следующее должно сделать:

@Override
public void init() {
    getServletContext().setAttribute("managedBeanName", new BackingBean());
}

Вот и все.Он будет доступен в JSF к #{managedBeanName}.

3 голосов
/ 19 июля 2011

Попробуйте FacesContext.currentInstance().getExternalContext().getApplicationMap().put(name, bean);, т.е. поместите экземпляр управляемого компонента на карту, используя имя, которое вы хотите использовать в выражениях.

Редактировать:

Чтобы зарегистрировать компонент, попробуйте вызвать:ApplicationAssociate.getCurrentInstance().getBeanManager().register(...) и сдайте ManagedBeanInfo заполненный вами.

1 голос
/ 04 сентября 2014

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

Использование:

UserBean ub = (UserBean) 
    Example.getBean(servletRequest, servletResponse, "user", UserBean.class);

Источник:

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

class Example {

    public static Object getBean(HttpServletRequest request, HttpServletResponse response, String beanName, Class expectedType){
        FacesContext ctx = getFacesContext(request, response);
        ValueExpression vex = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), "#{"+beanName+"}", expectedType);
        return vex.getValue(ctx.getELContext());
    }

    private static FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext == null) {
            facesContext = ((FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY)).
                getFacesContext(request.getSession().getServletContext(), request, response, 
                ((LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY))
                .getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE));

            InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);
            facesContext.setViewRoot(facesContext.getApplication().getViewHandler().createView(facesContext, ""));
        }
        return facesContext;
    }

    private abstract static class InnerFacesContext extends FacesContext {
        protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
            FacesContext.setCurrentInstance(facesContext);
        }
    }
}
0 голосов
/ 21 октября 2015

Допустим, я зарегистрировал свои bean-компоненты с помощью

ApplicationAssociate.getInstance(sc).getBeanManager().register(...)

Теперь все работает нормально, но затем происходит перезапуск сервера, и мои bean-компоненты уничтожаются. Как при запуске я могу зарегистрировать тот же bean-компонент.

...