2012-02-22 25 views
6

mam klasa abstrakcyjna AbstractService który ma odniesienie do AbstractDAOAutowire zależności od podklasy

class AbstractService{ 
    protected AbstractDAO abstractDAO; 
} 

AbstractService zostanie przedłużony o rzeczywistych klas usług jak ServiceClassA, ServiceClassB itp i AbstractDAO zostanie przedłużony o DaoClassA, DaoClassB itp

zależności od tego, która klasa rozciąga AbstractService, abstractDAO powinny być przykładem DaoClassA, DaoClassB itp

można to osiągnąć przez posiadanie setera abstractDAO w klasie rozciągającej jak

class ServiceClassA{  
    @Autowired 
    @Qualifier("daoClassA") 
    public void setAbstractDAO(AbstractDAO abstractDAO) { 
     super.abstractDAO = abstractDAO; 
    } 
} 

Czy istnieje jakiś sposób, aby mieć setter setAbstractDAO w AbstractService klasa sama i abstractDAO dostaje Autowired zależności od podklasa może wTH Spel + Qualifier etc

nie chcemy używać dowolnej konfiguracji XML dla tego

+0

Czy jest jakiś powód, dla którego nie można umieścić na przykład '@Apiowired DaoClassA dao' na' ServiceClassA'? Dlaczego pole musi być zadeklarowane w 'AbstractService'? – skaffman

+0

Świetne pytanie. Zawsze robiłem coś podobnego do opisywanego przez ciebie podejścia (nieco innego, ale tego samego podstawowego pomysłu) i zawsze chciałem czegoś bardziej automatycznego. Chętni do sprawdzenia, czy ktoś ma dobre podejście. –

+0

@skaffman W przypadkach, które miałem, chciałem, aby usługa AbstractService miała dostęp do AbstractDao, dzięki czemu mogłem napisać ogólne wersje operacji CRUD, między innymi. –

Odpowiedz

7

Nie zrobiłbym tego w ten sposób. Istotnie, istnieje duża szansa, że ​​ServiceClassA zależy od konkretnej metody DaoClassA. W takim przypadku musisz rzucić chronione AbstractDAO do DaoClassA za każdym razem, gdy chcesz wywołać taką konkretną metodę.

chciałbym uczynić rodzajowy i odwrócić drogę Zależności są wstrzykiwane:

public class AbstractService<T extends AbstractDAO> { 
    protected T dao; 

    protected AbstractService(T dao) { 
     this.dao = dao; 
    } 

    // methods common to all the services 
} 

public class ServiceClassA extends AbstractService<DaoClassA> { 
    @Autowired 
    public ServiceClassA(DaoClassA dao) { 
     super(dao); 
    } 

    // methods specific to ServiceClassA 
} 
+0

Jest to bardziej podobne do podejścia, z którego korzystałem w przeszłości i jest miło z tego powodu, o którym piszesz - typesafety in podklasa. Ale wciąż ma tę wadę, że wymaga punktów wtrysku specyficznych dla danego typu. Czy jest jakiś dobry sposób na uniknięcie tego? (Nie sądzę, że istnieje, ale jeśli ktoś go ma, chciałbym to wiedzieć.) –

+0

Ale nadal jest podobny do oryginalnego podejścia i wszystkie podklasy będą nadal musiały wykonać pracę –

+0

Możesz umieścić DaoClassA odniesienie w ServiceClassA, a teraz będzie specyficzne dla typu (bez odlewania). –

0

Nie, nie ma. Nie można uzyskać dostępu do nazwy klasy lub nazwy komponentu bean, która aktualnie wypełnia AutowiredAnnotationBeanPostProcessor z SPEL.

Można zastąpić AbstractBeanFactory.evaluateBeanDefinitionString i dodaćjako zmienną w BeanExpressionContext. Wtedy możesz wyprowadzić Dao z usługi. użycie SPEL w adnotacji @Value.

2

Rozwiązałem podobny problem, jak ty. Znalazłem inny sposób, nie musisz tworzyć metod ustawiania. Zamiast tego używaj zwykłych konstruktorów, ale używaj autowirowania Spring. Oto kompletny kod:

klasy serwisowe:

public abstract class AbstractService { 

    protected final AbstractDAO dao; 

    // Constructor forces you to inject dao in subclass 
    public AbstractService(final AbstractDAO dao) { 
     this.dao = dao; 
    } 

    public final void service() { 
     // you can do something generic here with 'dao' 
     // no matter which subclass is injected 
     this.dao.doSomething(); 
    } 
} 

@Component 
public class ServiceClassA extends AbstractService { 

    @Autowired 
    public ServiceClassA(@Qualifier("daoClassA") final AbstractDAO dao) { 
     super(dao); 
    } 

} 

@Component 
public class ServiceClassB extends AbstractService { 

    @Autowired 
    public ServiceClassB(@Qualifier("daoClassB") final AbstractDAO dao) { 
     super(dao); 
    } 

} 

Wskazówka @Qualifier("daoClassA") w konstruktorów podklasowymi

Zajęcia terenowe:

public interface AbstractDAO {  
    public void doSomething(); 
} 

@Component 
public class DaoClassA implements AbstractDAO { 

    @Override 
    public void doSomething() { 
     System.out.println("I am DaoClassA"); 
    }  
} 

@Component 
public class DaoClassB implements AbstractDAO { 

    @Override 
    public void doSomething() { 
     System.out.println("I am DaoClassB"); 
    }  
} 

I wreszcie, teraz możesz zadzwonić do usługi ogólnej z betonem Klasa serwisowa i betonowa klasa DAO: (oczywiście możesz je gdzieś przeprowadzić)

((AbstractService) context.getBean("serviceClassA")).service(); 
((AbstractService) context.getBean("serviceClassB")).service(); 

wypisze:

I am DaoClassA 
I am DaoClassB 
Powiązane problemy