我正在尝试编写一个自定义servlet(用于AJAX / JSON),在其中我想按名称引用我的@ManagedBeans。我希望映射:
http://host/app/myBean/myProperty
至:

@ManagedBean(name="myBean")
public class MyBean {
    public String getMyProperty();
}

是否可以从常规servlet中按名称加载bean?我可以使用JSF servlet或帮助程序吗?

我似乎对Spring感到宠爱,在Spring中所有这些都太明显了。

最佳答案

在基于servlet的 Artifact (例如@WebServlet@WebFilter@WebListener)中,您可以通过以下方法来获取“普通 Vanilla ” JSF @ManagedBean @RequestScoped:

Bean bean = (Bean) request.getAttribute("beanName");
@ManagedBean @SessionScoped通过:
Bean bean = (Bean) request.getSession().getAttribute("beanName");
@ManagedBean @ApplicationScoped通过:
Bean bean = (Bean) getServletContext().getAttribute("beanName");
请注意,这需要先由JSF自动创建bean。否则,这些将返回null。然后,您需要手动创建bean并使用setAttribute("beanName", bean)

如果您能够使用CDI @Named 代替自JSF 2.3弃用的@ManagedBean,那么它会更加容易,尤其是因为您不再需要手动创建bean了:
@Inject
private Bean bean;
请注意,这在您使用@Named @ViewScoped时将不起作用,因为只能通过JSF View 状态来标识该bean,并且仅在调用FacesServlet时才可用。因此,在此之前运行的过滤器中,访问@Inject@ViewScoped将始终抛出ContextNotActiveException

只有在@ManagedBean内部时,才可以使用 @ManagedProperty :
@ManagedProperty("#{bean}")
private Bean bean;
请注意,这在@Named@WebServlet或任何其他 Artifact 中不起作用。它实际上仅在@ManagedBean内部有效。

如果您不在@ManagedBean内,但是FacesContext随时可用(即FacesContext#getCurrentInstance()不返回null),则也可以使用 Application#evaluateExpressionGet() :
FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);
可以方便地进行以下操作:
@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
    FacesContext context = FacesContext.getCurrentInstance();
    return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}
可以如下使用:
Bean bean = findBean("bean");

也可以看看:
  • Backing beans (@ManagedBean) or CDI Beans (@Named)?
  • 09-05 15:59