Autowire в зависимости от подкласса - PullRequest
8 голосов
/ 22 февраля 2012

У меня есть абстрактный класс AbstractService, имеющий ссылку на AbstractDAO

class AbstractService{  
   protected AbstractDAO abstractDAO;  
}

AbstractService, который будет расширен фактическими классами обслуживания, такими как ServiceClassA, ServiceClassB и т. Д., И AbstractDAO будет расширен на DaoClassA, DaoClassB и т. Д.

В зависимости от того, какой класс расширяется * AbstractService, abstractDAO должен быть экземпляром DaoClassA, DaoClassB и т. Д.

Я могу добиться этого с помощью установщика abstractDAO в расширяющем классе, например

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

. Есть ли способ установить сеттер setAbstractDAO в самом классе AbstractService, а abstractDAO получит Autowired в зависимости отна подклассе может быть SPEL + Qualifier и т. д.

Мы не хотим использовать какую-либо конфигурацию XML для этого

Ответы [ 3 ]

7 голосов
/ 22 февраля 2012

Я бы так не поступил. Действительно, есть хороший шанс, что ServiceClassA зависит от какого-то конкретного метода DaoClassA. В этом случае вам придется приводить защищенный AbstractDAO к DaoClassA каждый раз, когда вы хотите вызвать такой конкретный метод.

Я бы сделал его универсальным и изменил бы способ введения зависимостей:

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
}
2 голосов
/ 23 января 2015

Я решал подобную проблему, как ты. Я нашел другой способ, вам не нужно создавать методы установки. Вместо этого используйте обычные конструкторы, но используйте автоматическое подключение Spring. Вот полный код:

Классы обслуживания:

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);
    }

}

Уведомление @Qualifier("daoClassA") в конструкторах подклассов

Классы полей:

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");
    }    
}

И, наконец, теперь вы можете вызывать свой общий сервис с конкретным классом Service и конкретным классом DAO: (конечно, вы можете подключить их где-нибудь автоматически)

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

напечатает:

I am DaoClassA
I am DaoClassB
0 голосов
/ 23 февраля 2012

Нет, нет.Вы не можете получить доступ к классу или имени компонента, который в настоящее время заполняет AutowiredAnnotationBeanPostProcessor из SPEL.

Вы можете переопределить AbstractBeanFactory.evaluateBeanDefinitionString и добавить beanDefinition в качестве переменной в BeanExpressionContext.Тогда вы можете получить Дао из Службы.использование SPEL в аннотации @Value.

...