2012-02-22 13 views
6

Tengo una clase abstracta AbstractService que tiene una referencia a AbstractDAOAutowire dependiendo de la subclase

class AbstractService{ 
    protected AbstractDAO abstractDAO; 
} 

AbstractService se extenderá por clases de servicios reales como ServiceClassA, ServiceClassB etc, y AbstractDAO se extenderá por DaoClassA, DaoClassB etc.

Dependiendo de la clase que se extienda AbstractService, abstractDAO debe ser una instancia de DaoClassA, DaoClassB etc

puedo lograr esto a través de la incubadora abstractDAO en la clase que se extiende como

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

¿Hay alguna manera de tener la incubadora setAbstractDAO en AbstractService clase misma y abstractDAO consigue Autowired dependiendo de la subclase tal wth SPEL + Calificador etc

no queremos utilizar cualquier configuración XML de este

+0

¿Hay alguna razón por la que no se puede poner, por ejemplo, '@Autowired DaoClassA dao' en' ServiceClassA'? ¿Por qué el campo debe declararse en 'AbstractService'? – skaffman

+0

Gran pregunta. Siempre he hecho algo similar al enfoque que describes (ligeramente diferente, pero la misma idea básica) y siempre he querido algo un poco más automático. Ansioso por ver si alguien tiene un buen enfoque. –

+0

@skaffman En casos que he tenido, quería que AbstractService tuviera acceso a AbstractDao para poder escribir versiones generales de las operaciones de CRUD, entre otras cosas. –

Respuesta

7

No lo haría así. De hecho, existe una buena posibilidad de que el ServiceClassA dependa de algún método específico de DaoClassA. En este caso, debería lanzar el AbstractDAO protegido a DaoClassA cada vez que desee llamar a un método tan específico.

que lo haría genérico, e invertir la forma en que se inyectan las dependencias:

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

Esto es más similar al enfoque que he usado en el pasado, y es bueno por la razón que usted nota - typesafety in la subclase. Pero todavía tiene la desventaja de que requiere puntos de inyección específicos del tipo. ¿Hay alguna buena manera de evitar eso? (No creo que exista, pero si alguien tiene uno, me gustaría saberlo). –

+0

Pero aún así es similar al enfoque original y todas las subclases todavía tendrán que hacer el trabajo –

+0

Puedes poner un DaoClassA referencia en el ServiceClassA y ahora será específico del tipo (sin conversión). –

0

No, no lo hay. No puede acceder al nombre de clase o bean que actualmente está rellenando el AutowiredAnnotationBeanPostProcessor desde SPEL.

Puede anular AbstractBeanFactory.evaluateBeanDefinitionString y agregar beanDefinition como variable en el BeanExpressionContext. Entonces puedes derivar el Dao del Servicio. usando SPEL en la anotación @Value.

2

Estaba resolviendo problema similar al tuyo. Encontré otra manera, no tienes que crear métodos setter. En lugar de, use constructores regulares, pero use Spring autowiring. Aquí está el código completo:

clases de servicio:

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

} 

Aviso @Qualifier("daoClassA") en los constructores de subclases

clases de campo:

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

Y, por último, ahora se puede llamar a su servicio genérico con la clase de servicio concreta y la clase DAO concreta: (por supuesto, puedes autoconectarlos en algún lugar)

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

imprimirá:

I am DaoClassA 
I am DaoClassB