2012-05-16 8 views
7

Używam Spring i JSF 2 do tworzenia aplikacji internetowych. Przedmiotem działalności są przechowywane w pojemniku na wiosnę, a ja je wstrzykiwać w Managed Beans pomocą @ManagedProperty, tak:Jak ponownie wstrzyknąć transient @ ManagedProperty przy deserializacji?

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Getter @Setter 
    @ManagedProperty("#{someService}") 
    private SomeService someService; 
    // ... 

Problem polega na tym, trzymam coraz NotSerializableException dla klasy od wiosny (ServiceLocatorFactoryBean), który jest używany przez komponent bean SomeService SomeService.

Jeśli zrobię to transient, w jaki sposób mogę wykonać ponowne wstrzyknięcie po deserializacji?

Albo, jakie byłyby inne sposoby rozwiązania tego problemu?

Czytałem tutaj kilka innych podobnych pytań, ale nie mogłem znaleźć żadnego rozwiązania tego problemu.

+2

FYI: ten problem nie występuje, gdy używasz tylko EJB Java EE zamiast Spring. – BalusC

+0

@BalusC Tak, czytałem o tym w innych pytaniach, niestety nie wiem wystarczająco dużo o EJB, aby go jeszcze użyć (i nie wiem, czy mógłbym przekonać współpracowników, aby pozwolili mi spróbować tego projektu) . Czy możesz wskazać mi dobry zasób, żeby się o tym dowiedzieć? – elias

+0

To nie jest takie trudne. Tylko upewnij się, że twój kontener obsługuje już EJB (Glassfish, JBoss, Weblogic, itp.). Opisz klasę usług za pomocą '@ Stateless' lub' @ Stateful' i wpisz "@ EJB". to jest to! Nie ma potrzeby pobierania/ustawiania btw. – BalusC

Odpowiedz

3

Zamiast wstrzykiwanie fasolę Wiosenne pośrednictwem EL w @ManagedProperty adnotacji (wykonywane na ManagedBean inicjalizacji), uzyskanie ziarna oceniające EL przy starcie.

Z takim podejściem, to co ziarna JSF powinna wyglądać następująco:

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private static SomeService someService() { 
     return SpringJSFUtil.getBean("someService"); 
    } 
    // ... 

a klasa użyteczności SpringJSFUtil.java że dostaje fasoli poprzez EL:

import javax.faces.context.FacesContext; 

public class SpringJSFUtil { 

    public static <T> T getBean(String beanName) { 
     if (beanName == null) { 
      return null; 
     } 
     return getValue("#{" + beanName + "}"); 
    } 

    @SuppressWarnings("unchecked") 
    private static <T> T getValue(String expression) { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     return (T) context.getApplication().evaluateExpressionGet(context, 
       expression, Object.class); 
    } 
} 

Eliminuje właściwość Spring bean (kosztem wykonania kilku innych ocen EL), unikając w ten sposób wszystkich problemów związanych z serializacją posiadania właściwości na pierwszym miejscu.

To samo podejście, używając OmniFaces:

W moim rzeczywisty kod, używam metody z utility class dostępny od OmniFacesevaluateExpressionGet(String expression). Tak więc, dla tych z Was, którzy używają go też, to właśnie mój kod naprawdę wyglądać następująco:

import static org.omnifaces.util.Faces.evaluateExpressionGet; 

@ManagedBean 
@ViewScoped 
public class SomeMB implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private static SomeService someService() { 
     return evaluateExpressionGet("#{someService}"); 
    } 
    // ... 

Zauważ, że tutaj metoda dostaje pełną EL („# {wyrażenie}”), a nie tylko na wiosnę nazwa fasoli (lub otrzymasz wyjątek ClassCastException).

-1

Dobrze o tym pamiętać z podręcznika sprężyna ( link to spring):

Konstruktor opartych lub seter opartej DI?

Ponieważ można mieszać DI, zarówno konstruktora, jak i Settera, jest to dobra zasada, aby używać argumentów konstruktora dla obowiązkowych zależności i ustawiających dla zależności opcjonalnych. Zauważ, że użycie @ Adnotacji wymaganej na setera może być użyte do ustalenia zależności wymaganych przez ustawiacze.

Zespół wiosenny ogólnie opowiada się za zastrzykiem ustawiającym, ponieważ duża liczba argumentów konstruktora może stać się nieporęczna, szczególnie gdy właściwości są opcjonalne. Metody setera również sprawiają, że obiekty tej klasy są zdolne do ponownej konfiguracji lub ponownego wtrysku później. Zarządzanie przez JMX MBeans jest przekonującym przykładem użycia.

Niektórzy puryści preferują zastrzyki oparte na konstruktorze. Dostarczenie wszystkich zależności obiektów oznacza, że ​​obiekt jest zawsze zwracany do klienta (wywoływania) w całkowicie zainicjalizowanym stanie. Wadą jest to, że obiekt staje się mniej podatny na rekonfigurację i ponowne wstrzyknięcie.

Użyj DI, który najlepiej pasuje do konkretnej klasy. Czasami, gdy zajmujesz się zajęciami osób trzecich, do których nie masz źródła, wybór jest dla Ciebie. Starsza klasa może nie ujawniać żadnych metod ustawiających, a zatem wtrysk konstruktora jest jedynym dostępnym DI.

+0

Przepraszam, nie podążam za ... Co ma do czynienia z moim problemem z bazującym na konstruktorze i ustawiającym DI? – elias

2

Wypróbuj @Scope (wartość = BeanDefinition.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.INTERFACES) w usłudze Spring @Service. To powinno wstrzyknąć serializowalny obiekt proxy do zarządzanego komponentu bean, który przeniesie usługę po uzyskaniu dostępu po deserializacji.

0

Dla tych, którzy śledzą - miałem podobny problem z wstrzykniętym zasobem ResourceBundle. Korzystanie część odpowiedzi BalusC jest, zrobiłem co następuje:

@ManagedProperty(value="#{myBundle}") 
private transient ResourceBundle myBundle; 

private Object readResolve() { 
    myBundle = FacesContext.getCurrentInstance().getApplication() 
     .evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{myBundle}", 
     ResourceBundle.class); 
    return this; 
} 

ten sposób EL oceniana jest tylko wtedy, gdy udało fasola jest rozszeregować.

Powiązane problemy