当前位置: 首页 > 面试题库 >

JSF-会话范围的托管bean没有在会话反序列化上重新注入依赖项

孙夕
2023-03-14
问题内容

我不确定我在做什么是错误的,还是只是错过了某个地方的注释或配置项。情况如下:

我有一个JSF应用程序,其会话范围的bean名为SessionDataApplicationData在创建时,此Bean
注入了一个应用程序范围的Bean引用(类型)。首次创建会话时,此方法正常。依赖项注入是通过文件中的<managed-bean>元素完成的,faces- config.xml如下所示:

<managed-bean>
    <managed-bean-name>sessionData</managed-bean-name>
    <managed-bean-class>my.package.SessionData</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
        <property-name>applicationData</property-name>
        <property-class>my.package.ApplicationData</property-class>
        <value>#{applicationData}</value>
    </managed-property>
</managed-bean>
<managed-bean>
    <managed-bean-name>applicationData</managed-bean-name>
    <managed-bean-class>my.package.ApplicationData</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

因为序列化时让我的SessionData对象包含ApplicationData对象没有意义,所以我在对象中将ApplicationData引用标记为瞬态SessionData

transient private ApplicationData applicationData;

直到停止Web应用程序(在我的Tomcat
6.x容器中)并序列化会话之前,一切都很好。当我重新启动应用程序并且反序列化会话时ApplicationData,JSF不会重新插入对我的引用。我知道反序列化应该使瞬态字段没有值。
是否有一种方法可以向JSF发出信号,告知该会话范围的对象要求在反序列化之后再次设置其依赖项?

我将MyFaces JSF 1.2和Tomcat 6.0.26用作Web应用程序容器。


问题答案:

尽管Bozho提供的解决方案可行,但我不想将代理对象引入当前未使用它们的应用程序中。我的解决方案不理想,但是可以完成工作。

我将瞬变场留在原处:

transient private ApplicationData _applicationData;

我还保留了setter,以便JSF可以SessionData在首次创建对象时初始设置引用:

public void setApplicationData(ApplicationData applicationData) {
    _applicationData = applicationData;
}

我所做的更改是使用getter方法进行的。SessionData现在,该对象中的方法需要停止直接访问该_applicationData字段,而是通过getter获取引用。吸气剂将首先检查空引用。如果为null,则通过来获取托管bean
FacesContext。这里的约束是,FacesContext仅在请求的生命周期内可用。

/**
 * Get a reference to the ApplicationData object
 * @return ApplicationData
 * @throws IllegalStateException May be thrown if this method is called
 *  outside of a request and the ApplicationData object needs to be
 *  obtained via the FacesContext
 */
private ApplicationData getApplicationData() {
    if (_applicationData == null) {
        _applicationData = JSFUtilities.getManagedBean(
            "applicationData",  // name of managed bean
            ApplicationData.class);
        if (_applicationData == null) {
            throw new IllegalStateException(
                "Cannot get reference to ApplicationData object");
        }
    }
    return _applicationData;
}

如果有人在意,这是我的getManagedBean()方法的代码:

/**
 * <p>Retrieve a JSF managed bean instance by name.  If the bean has
 * never been accessed before then it will likely be instantiated by
 * the JSF framework during the execution of this method.</p>
 * 
 * @param managedBeanKey String containing the name of the managed bean
 * @param clazz Class object that corresponds to the managed bean type
 * @return T
 * @throws IllegalArgumentException Thrown when the supplied key does
 *  not resolve to any managed bean or when a managed bean is found but
 *  the object is not of type T
 */
public static <T> T getManagedBean(String managedBeanKey, Class<T> clazz)
        throws IllegalArgumentException {
    Validate.notNull(managedBeanKey);
    Validate.isTrue(!managedBeanKey.isEmpty());
    Validate.notNull(clazz);
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (facesContext == null) {
        return null;
    }
    Validate.notNull(facesContext.getApplication());
    ELResolver resolver = facesContext.getApplication().getELResolver();
    Validate.notNull(resolver);
    ELContext elContext = facesContext.getELContext();
    Validate.notNull(elContext);
    Object managedBean = resolver.getValue(
        elContext, null, managedBeanKey);
    if (!elContext.isPropertyResolved()) {
        throw new IllegalArgumentException(
            "No managed bean found for key: " + managedBeanKey);
    }
    if (managedBean == null) {
        return null;
    } else {
        if (clazz.isInstance(managedBean)) {
            return clazz.cast(managedBean);
        } else {
            throw new IllegalArgumentException(
                "Managed bean is not of type [" + clazz.getName() +
                "] | Actual type is: [" + managedBean.getClass().getName()+
                "]");
        }
    }
}

而且不要接听我的验证电话。开发完成后,我将其淘汰!:)



 类似资料:
  • 我用的是Mojarra 2.1。29并具有会话范围的JSF托管bean 和一个Spring的豆子: 事实上,我需要JSF中的某种自定义范围,即在满足条件时从头开始重新创建bean。有可能以某种方式做吗?通过重新创建,我的意思是在第一次创建时清理它的所有属性。

  • 我已经对Spring bean使用的注释进行了注释。我通过spring DI成功地创建了相同的bean,并设置了对象注入的范围。现在,我想用Struts2和di做同样的事情。为此,我在中创建了bean定义 和简单的操作来创建bean并将其注入到我的操作中 在JSP中,我在会话bean上使用简单的迭代器 null

  • 我编写了一个会话范围的托管bean,用于在domino xpages应用程序中缓存sesion用户特定的信息,如下代码所示: 然后,我在faces配置中声明了它,使其成为会话范围的bean: 在测试bean时,我通过#{NBUser.fullUserName}使用它,它并不总是返回当前domino http会话上下文的用户,例如,我首先由用户“user1”登录并注销,然后由user2登录,bean

  • 在JSF1.2应用程序中,我是否可以覆盖使用子类返回的会话范围的托管Bean? 阶级结构 我有一个会话范围的托管Bean,,及其子类,: 面配置。xml 问题陈述 EL表达式返回的实例。 我想用的实例重新绑定名称,以便EL表达式为会话的其余部分返回子类的实例。 有没有办法实现我的目标? 激励范例 处理应用程序主页后面的GUI逻辑。当用户从专用登录页面进入应用程序时,我需要提供一个受限的、简化的主页

  • 我有一个会话范围的CDI托管bean: 在某个流之后,我需要从会话中删除这个bean,对于该流,我使用了以下代码,如下面的答案所示: 但是,它不起作用,仍然留在会话中。 我是否遗漏了什么?

  • 我在解决如何正确处理JSF中会话的自动销毁方面遇到了困难。当然,此时,容器会使会话失效,从而也会在会话范围的bean上调用@PreDestroy方法。 在某些会话范围bean的预销毁中,我们正在注销一些侦听器,如下所示: 然而,getWS()方法实际上试图获取对另一个会话范围bean的引用,但失败了,如返回null。Ryan Lubke认为,后者似乎是正常的JSF行为: 我们遵守这里的规范。我不确