JSF - 会话范围的托管bean没有重新注入会话反序列化的依赖关系 [英] JSF - Session-scoped managed bean does not have dependencies re-injected on session deserialization

查看:99
本文介绍了JSF - 会话范围的托管bean没有重新注入会话反序列化的依赖关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道我在做什么是错误的,或者我刚刚错过了某个注释或配置项。以下是这种情况:



我有一个名为 SessionData 的会话作用域的JSF应用程序。此Bean在创建时注入了一个应用程序范围的bean引用(类型为$ code> ApplicationData )。当会话第一次创建时,这可以正常工作。依赖注入通过 faces-config.xml 文件中的< managed-bean> 元素完成,如下所示:

 < 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>应用程序< / managed-bean-scope>
< / managed-bean>

因为我的 SessionData object在序列化时包含 ApplicationData 对象,我将 ApplicationData 引用标记为 code> SessionData object:

  transient private ApplicationData applicationData; 

直到Web应用程序停止(在Tomcat 6.x容器中)和会话被序列化。当我重新启动应用程序并且会话被反序列化时,我对JSF不再重新注入对 ApplicationData 的引用。我知道反序列化应该是暂时的,没有价值的。



我正在使用MyFaces JSF 1.2,这是一种方法来表示JSF,这个会话范围的对象需要在反序列化之后再次设置它的依赖项和Tomcat 6.0.26作为我的Web应用程序容器。

解决方案

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



我离开了瞬态字段:

  transient private ApplicationData _applicationData; 

我也将设置器置于原位,所以JSF最初可以在 SessionData 对象是第一次创建:

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

我所做的更改是在getter方法中。现在, SessionData 对象中的方法现在需要停止直接访问 _applicationData 字段,而通过getter获取引用。 getter将首先检查一个null引用。如果为空,则通过 FacesContext 获取受管Bean。这里的约束是 FacesContext 仅在请求的使用期限内可用。

  / ** 
*获取对ApplicationData对象的引用
* @return ApplicationData
* @throws IllegalStateException如果此方法称为
*,则可能会抛出一个请求和ApplicationData对象需要
*通过FacesContext
* /
私有ApplicationData getApplicationData(){
if(_applicationData == null){
_applicationData = JSFUtilities.getManagedBean(
applicationData,//托管bean的名称
ApplicationData.class);
if(_applicationData == null){
throw new IllegalStateException(
无法获取ApplicationData对象的引用);
}
}
return _applicationData;
}

如果有人关心,这里是我的 getManagedBean()方法:

  / ** 
*< p> JSF通过名称管理bean实例。如果bean的
*从未被访问过,那么在执行此方法期间可能会由
*的JSF框架实例化。< / p>
*
* @param managedBeanKey包含托管bean的名称的字符串
* @param clazz对应于受管Bean类型的类对象
* @return T
* @throws IllegalArgumentException当提供的键
*不解析为任何受管Bean或找到受管Bean但
*时,抛出此对象不是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);
对象managedBean = resolver.getValue(
elContext,null,managedBeanKey);
if(!elContext.isPropertyResolved()){
throw new IllegalArgumentException(
找不到托管bean:+ managedBeanKey);
}
if(managedBean == null){
return null;
} else {
if(clazz.isInstance(managedBean)){
return clazz.cast(managedBean);
} else {
throw new IllegalArgumentException(
托管bean不是类型+ clazz.getName()+
] |实际类型是:[+ managedBean .getClass()。getName()+
]);
}
}
}

不要选择我的验证电话。完成开发后我会把它们拿出来:)


I'm not sure if what I'm doing is wrong, or if I just missed an annotation or configuration item somewhere. Here's the situation:

I have a JSF application with a session-scoped bean named SessionData. This bean has an application-scoped bean reference (of type ApplicationData) injected into it at creation time. This works ok when the session is first created. The dependency injection is done with <managed-bean> elements in the faces-config.xml file as shown here:

<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>

Because it doesn't make sense to have my SessionData object include the ApplicationData object when it is serialized, I have marked the ApplicationData reference as transient in my SessionData object:

transient private ApplicationData applicationData;

All is good until the web application is stopped (in my Tomcat 6.x container) and the sessions are serialized. When I restart the application and the sessions are deserialized, my reference to ApplicationData is not re-injected by JSF. I know that deserialization is supposed to leave transient fields without a value. Is there a way to signal JSF that this session-scoped object requires its dependencies be set again after deserialization?

I am using MyFaces JSF 1.2 and Tomcat 6.0.26 as my web application container.

解决方案

Although the solution offered by Bozho could work, I don't want to introduce proxy objects into an application that isn't currently using them. My solution is less than ideal, but it gets the job done.

I left the transient field in place:

transient private ApplicationData _applicationData;

I also left the setter in place so JSF can initially set the reference when the SessionData object is created the first time:

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

The change that I made was in the getter method. Methods in the SessionData object now need to stop directly accessing the _applicationData field and instead get the reference via the getter. The getter will first check for a null reference. If it is null, then the managed bean is obtained via the FacesContext. The constraint here is that the FacesContext is only available during the lifespan of a request.

/**
 * 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;
}

If anyone cares, here is the code for my getManagedBean() method:

/**
 * <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()+
                "]");
        }
    }
}

And don't pick on my Validate calls. I'll take them out after I'm done with development! :)

这篇关于JSF - 会话范围的托管bean没有重新注入会话反序列化的依赖关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆