我不确定我所做的是错误的,还是我只是在某个地方漏掉了一个注释或配置项。情况如下:
我有一个JSF应用程序,它的会话作用域bean名为SessionData。此bean在创建时有一个应用程序范围的bean引用(类型为ApplicationData)注入其中。这在第一次创建会话时工作正常。依赖项注入是在<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对象包含它是没有意义的,所以我在SessionData对象中将ApplicationData引用标记为瞬态的:
transient private ApplicationData applicationData;在停止web应用程序(在我的Tomcat 6.x容器中)并序列化会话之前,一切都很好。当我重新启动应用程序并且会话被反序列化时,我对ApplicationData的引用不会被JSF重新注入。我知道反序列化应该会使瞬态字段没有值。是否有一种方法可以向JSF发出信号:这个会话作用域对象需要在反序列化之后再次设置它的依赖项?
我使用MyFaces JSF1.2和Tomcat6.0.26作为我的web应用程序容器。
发布于 2010-09-23 15:45:28
尽管Bozho提供的解决方案可以工作,但我不想将代理对象引入到目前不使用代理对象的应用程序中。我的解决方案不太理想,但它完成了任务。
我把瞬变场留在原处:
transient private ApplicationData _applicationData;我还保留了setter,这样JSF可以在第一次创建SessionData对象时首先设置引用:
public void setApplicationData(ApplicationData applicationData) {
_applicationData = applicationData;
}我所做的改变是用getter的方法。SessionData对象中的方法现在需要停止直接访问_applicationData字段,而是通过getter获取引用。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()+
"]");
}
}
}别挑我的验证电话。在我完成开发工作后,我会把它们拿出来!:)
发布于 2010-09-23 12:35:10
您可以添加一个方法:
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
applicationData = initializeApplicationData();
}在initializeApplicationData中,您可以使用动态代理对象。使用CGLIB或javassist创建一个代理,在每次方法调用之前设置一个内部字段--真正的ApplicationData。如果是null,那么获取当前的FacesContext (在这一点上将是可访问的),并通过以下方法从那里获取托管bean:
FacesContext facesContext = FacesContext.getCurrentInstance();
originalApplicationData = (ApplicationData)facesContext.getApplication()
.createValueBinding("#{applicationData}").getValue(facesContext);并委托给它的方法。
这是一个丑陋的解决办法,但我认为它会奏效的。
https://stackoverflow.com/questions/3778353
复制相似问题