Я хочу зарегистрировать/добавить управляемый Bean класс программно (изнутри сервлета init()) в область приложения. Как я могу сделать это с помощью JSF 1.2?
Как программно зарегистрировать управляемый JSF bean?
Ответ 1
из сервлета
init()
Итак, это касается запроса, не связанного с JSF. FacesContext#getCurrentInstance()
вернет null
здесь, поэтому он вам не нужен.
Хорошо знать, что управляемое beans приложение с поддержкой JSF хранится в основном как атрибут ServletContext
. В методе init()
у вас есть ServletContext
унаследованным методом getServletContext()
. Итак, следующее:
@Override
public void init() {
getServletContext().setAttribute("managedBeanName", new BackingBean());
}
Что это. Он будет доступен в JSF #{managedBeanName}
.
Ответ 2
Вряд ли это может сделать это программным образом из вашего приложения для управляемого beans всех областей. BalusC уже указал, как это сделать для управляемого приложениями beans.
Взглянув на то, как управляемые beans зарегистрированы в Mojarra 2.1 (реализация JSF 2.1); нет очень много элегантных вариантов, доступных для программной регистрации сеанса и запроса с охватом beans. Проще говоря, вы либо должны будете ссылаться на конкретные классы реализации, либо вам придется создавать и уничтожать, то есть управлять самим beans, а не полагаться на реализацию JSF, чтобы сделать это.
Заполнение областей запроса и сеанса с помощью beans (неуправляемого способа)
Примечание. Это называется "неуправляемым способом", поскольку вы создаете beans, а не контейнер. Аннотации, такие как @PostConstruct
и @PreDestroy
, не будут работать, если вы не обработаете их самостоятельно и не вызовите соответствующие методы. Даже инъекция зависимости не будет работать.
EL-выражения всегда оцениваются во время выполнения, поэтому он дает вам достаточно возможности заполнить область с помощью beans перед оценкой (что позволяет снимать себя в ногу, если у вас есть такая возможность). В Mojarra (и, возможно, в других реализациях JSF) EL-резольвер будет полагаться на службы ScopeHandler (или эквивалентного класса) для разрешения значений выражения EL. Mojarra использует классы 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
- это тот, который содержит управляемые регистрации bean, а в следующем разделе обсуждается, как "взломать" процесс регистрации Mojarra.
Использование классов Mojarra для регистрации beans
Регистрация управляемого beans в реализации Mojarra выполняется методом public void register(ManagedBeanInfo beanInfo)
класса com.sun.faces.mgbean.BeanManager
. Нетрудно получить доступ к классу BeanManager
, используя только JSF или Servlet API. Однако существует класс ApplicationAssociate
Mojarra, который создает экземпляр BeanManager
и может быть доступен с помощью метода getCurrentInstance()
. Другой ответ Томаса уже показывает, как программно зарегистрировать управляемый bean:
ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)
Существует оговорка с вышеуказанным подходом. Маловероятно, что этот подход будет работать в методе init Servlet
по той простой причине, что метод getCurrentInstance
полагается на переменную ThreadLocal для извлечения экземпляра ApplicationAssociate
. Локальная переменная потока инициализируется классом com.sun.faces.application.WebappLifecycleListener
, поэтому вы должны воспроизвести механизм, используемый классом WebappLifecycleListener
, для вызова метода ApplicationAssociate getInstance(ServletContext context)
, чтобы получить доступ к экземпляру ApplicationAssociate
. Таким образом, следующий код может быть (поскольку я не пытался его использовать) лучше, если вы хотите использовать определенные классы Mojarra:
ServletContext sc = ... //get the ServletContext reference;
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)
Вы все равно должны следить за причудами, возникающими из этого механизма, так как вполне возможно, что некоторые из классов и экземпляров Mojarra не были загружены или инициализированы до вашего сервлета. Поэтому я предлагаю загрузиться, пытаясь настроить ваш сервлет с load-on-startup
значением, которое больше, чем значение, используемое FacesServlet
.
Ответ 3
Попробуйте FacesContext.currentInstance().getExternalContext().getApplicationMap().put(name, bean);
, т.е. поместите управляемый экземпляр bean на карту, используя имя, которое вы хотите использовать в своих выражениях.
Изменить:
Чтобы зарегистрировать bean, попробуйте позвонить: ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)
и передать ManagedBeanInfo
, который вы заполнили.
Ответ 4
Следующий код регистрирует управляемый bean с использованием FacesContext
, но для этого требуется запрос и ответ сервлета. Вы можете использовать код и инициализировать его лениво, используя сервлет, а не во время init.
Использование:
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);
}
}
}
Ответ 5
Скажем, я зарегистрировал свой beans с помощью
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)
Теперь он работает нормально, но затем перезапускается сервер и my beans уничтожены. Как при запуске я могу зарегистрировать тот же bean.