2010-09-23 21 views
8

Yaptığım şeyin yanlış olup olmadığından emin değilim, ya da bir açıklama ya da yapılandırma öğesinin bir noktasını kaçırdım.JSF - Oturumla yönetilen yönetilen fasulyenin, oturumun kaldırılması sırasında yeniden enjekte edilen bağımlılıkları yok

Ben SessionData adında bir oturum kapsamlı fasulye ile bir JSF uygulama var: İşte durum bu. Bu fasülyenin, yaratılış süresinde enjekte edilmiş bir uygulama-kapsamlı fasulye referansı (tip ApplicationData) vardır. Bu, oturum ilk oluşturulduğunda işe yarıyor. burada gösterildiği gibi bağımlılık enjeksiyon faces-config.xml dosyada <managed-bean> elemanları ile yapılır: bu tefrika olduğunda benim SessionData nesne olması mantıklı değil çünkü

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

ApplicationData nesneyi içerir, ben ApplicationData referansı işaretlediğiniz benim SessionData nesnesindeki geçici olarak: web uygulaması (benim Tomcat 6.x kapta) durdurulur ve oturumlar serileştirildi kadar

transient private ApplicationData applicationData; 

Tüm iyidir. Uygulamayı yeniden başlattığımda ve oturumlar seri hale getirildiğinde, ApplicationData numaralı referansa JSF tarafından yeniden enjekte edilmiyor. Deserialization'un geçici alanları değersiz bırakması gerektiğini biliyorum. JSF'ye bu oturum kapsamındaki nesnenin seri hale getirilmesinden sonra bağımlılıklarının yeniden ayarlanmasını gerektirdiğini bildirmenin bir yolu var mı?

benim web uygulama kapsayıcı olarak MyFaces JSF 1.2 ve Tomcat 6.0.26 kullanıyorum.

+1

Bir readObject() yöntemini sağladığım ve FacesContext kullanarak seri hale getirme sırasında orada ApplicationData nesnesini el ile ayarlamanız önerildi. FacesContext sadece bir talep ömrü boyunca kullanılabilir beri işe yaramaz sanmıyorum. Uygulama başlangıcında serileştirme gerçekleşiyor. –

+2

doğru, bu yüzden cevabımı sildim. Daha karmaşık görünüyor (bu nedenle soru için +1) – Bozho

cevap

5

Bozho tarafından sunulan çözüm işe yarayabilse de, proxy nesnelerini şu anda kullanmayan bir uygulamaya sokmak istemiyorum. Benim çözümüm idealden daha az, ama işi bitiriyor.

Ben yerinde geçici alanını terk:

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

: MTU başlangıçta SessionData nesne ilk kez oluşturulduğunda başvuru ayarlayabilirsiniz yüzden de yerinde ayarlayıcı bıraktı

transient private ApplicationData _applicationData; 

Yaptığım değişiklik, getter yöntemindeydi. SessionData nesnesindeki yöntemlerin şimdi _applicationData alanına doğrudan erişmesi ve bunun yerine alıcı aracılığıyla referansı alması gerekir. Alıcı ilk önce boş bir referans için kontrol edecektir. Boşsa, yönetilen fasulye FacesContext aracılığıyla elde edilir. Buradaki kısıtlama, FacesContext'un yalnızca bir talebin ömrü boyunca kullanılabilir olmasıdır.

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

kimse umurunda istersen, işte getManagedBean() yöntemine ilişkin koddur:

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

Ve doğrula çağırır üzerinde seçmem. Gelişim bittikten sonra onları çıkaracağım!

+4

['Application # assessExpressionGet() ']' da bir kısayol var (http://download.oracle.com/javaee/6/api/javax/faces/application/ Application.html # evaluateExpressionGet% 28javax.faces.context.FacesContext,% 20java.lang.String,% 20java.lang.Class% 29). Ayrıca bkz. [Bu cevap] (http://stackoverflow.com/questions/2633112/jsf-get-managed-bean-by-name/2633733#2633733). – BalusC

1

bir yöntem ekleyebilirsiniz:

private void readObject(java.io.ObjectInputStream in) 
throws IOException, ClassNotFoundException { 
    in.defaultReadObject(); 
    applicationData = initializeApplicationData(); 
} 

Ve initializeApplicationData yılında dinamik bir proxy nesnesi kullanabilirsiniz. CGLIB veya javassist kullanarak, her yöntem çağırma önce bir iç alan - gerçek ApplicationData gerçek kılan bir proxy oluşturun. o null ise, o olsun akım FacesContext (bu noktada erişilebilir olacaktır) ve oradan yönetilen fasulye alıyorum:

FacesContext facesContext = FacesContext.getCurrentInstance(); 
originalApplicationData = (ApplicationData)facesContext.getApplication() 
    .createValueBinding("#{applicationData}").getValue(facesContext); 

ve yöntemlere temsilci.

Bu çirkin bir çözümdür, ancak çalışacağını düşünüyorum.

+0

Bu benim ilk kez javassist kullanacağım, bu yüzden çözümünüzün bir kısmını sindirmek için biraz zamana ihtiyacım var. Teşekkür ederim. –

+0

oldukça kolaydır. Sadece öğreticiyi takip edin - proxy durumunuz en basittir :) – Bozho