如何以编程方式注册JSF托管bean?

Zee*_*mee 11 java jsf servlets managed-bean

我想以编程方式(从Servlet init()内)注册/添加Managed Bean类到应用程序范围.我怎么能用JSF 1.2做到这一点?

Vin*_*lds 19

从您的所有范围的托管bean应用程序中,不太可能以编程方式执行此操作.BalusC已经指出了如何为应用程序范围的托管bean执行此操作.

看了一下如何在Mojarra 2.1(JSF 2.1实现)中注册托管bean; 没有很多优雅的选项可用于会话和请求范围bean的程序化注册.简单地说,您要么必须调用特定于实现的类,要么必须创建和销毁,即自己管理bean而不是依赖于JSF实现来执行此操作.

使用bean填充请求和会话范围(非托管方式)

注 - 这被称为"非托管方式",因为您正在构建bean,而不是容器.注释喜欢@PostConstruct@PreDestroy不会工作,除非您自己处理它们并调用适当的方法.即使依赖注入也行不通.

EL表达式总是在运行时进行评估,因此它为您提供了足够的机会在评估之前使用bean填充范围(如果您有机会,可以让自己在脚下拍摄).在Mojarra(以及可能的其他JSF实现)中,EL解析器将依赖ScopeHandler(或等效类)的服务来解析EL表达式值.Mojarra使用类ApplicationScopeHandler,RequestScopeHandlerSessionScopeHandler从不同的范围获取值.

您可以在创建新会话之后,或者在JSF实现处理请求之前填充会话和请求范围的内容.

可以使用以下方式完成会话范围填充(理想情况下使用a HttpSessionListener):

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

keyname必须使用的是引用在EL表达式豆的值相匹配.

以类似的方式,您可以使用以下方法填充请求范围(最好在过滤器中完成):

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

如果您需要了解如何工作的,你应该看一看类com.sun.faces.context.SessionMap,com.sun.faces.context.RequestMap以及com.sun.faces.context.ApplicationMap怎么看上下文映射在内部管理,并通过使用SessionScopeHandler,RequestScopeHandlerApplicationScopeHandler这是静态内部类的类ScopeManager(另一种静态内部)类的在com.sun.faces.mgbean.BeanManager类.本BeanManager类是包含托管bean注册了一个,和下一节讨论如何"侵入"钻嘴鱼科的注册过程.

使用Mojarra类来注册bean

Mojarra实现中托管bean的注册是通过类的public void register(ManagedBeanInfo beanInfo)方法完成的com.sun.faces.mgbean.BeanManager.仅BeanManager使用JSF或Servlet API 访问该类并非易事.然而ApplicationAssociate,Mojarra类创建了BeanManager实例,可以使用该getCurrentInstance()方法访问.Thomas的另一个答案已经演示了如何以编程方式注册托管bean:

ApplicationAssociate.getCurrentInstance().getBeanManager().register(...)
Run Code Online (Sandbox Code Playgroud)

上述方法有一个警告.Servlet由于该getCurrentInstance方法依赖于ThreadLocal变量来检索ApplicationAssociate实例,因此这种方法不太可能在init方法中起作用.线程局部变量由com.sun.faces.application.WebappLifecycleListener类初始化,因此您必须重现WebappLifecycleListener该类使用的机制,即调用该ApplicationAssociate getInstance(ServletContext context)方法,以获得对该ApplicationAssociate实例的访问权限.因此,如果您愿意使用Mojarra特定类,则以下代码可能(因为我没有尝试使用它)更好的代码:

ServletContext sc = ... //get the ServletContext reference;
ApplicationAssociate.getInstance(sc).getBeanManager().register(...)
Run Code Online (Sandbox Code Playgroud)

您仍然必须注意由此机制引起的怪癖,因为很可能在Servlet之前没有加载或初始化某些Mojarra类和实例.因此,我建议加载尝试配置您的servlet的load-on-startup值高于FacesServlet.


Bal*_*usC 13

来自Servlet init()

因此,它涉及非JSF请求.该FacesContext#getCurrentInstance()会回到null这里,所以在这里是没有用的你.

很高兴知道JSF应用程序范围的托管bean基本上存储为.的属性ServletContext.在init()方法中,您可以ServletContext通过继承的getServletContext()方法掌握它.所以,以下应该做:

@Override
public void init() {
    getServletContext().setAttribute("managedBeanName", new BackingBean());
}
Run Code Online (Sandbox Code Playgroud)

而已.它将在JSF中提供#{managedBeanName}.