Antecedentes:
Tengo una aplicación Spring 2.5 / Java / Tomcat. Existe el siguiente bean, que se utiliza en toda la aplicación en muchos lugares.
public class HibernateDeviceDao implements DeviceDao
y el siguiente bean que es nuevo:
public class JdbcDeviceDao implements DeviceDao
El primer bean está configurado de esta manera (todos los beans en el paquete están incluidos)
<context:component-scan base-package="com.initech.service.dao.hibernate" />
El segundo bean (nuevo) se configura por separado
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
<property name="dataSource" ref="jdbcDataSource">
</bean>
Esto resulta (por supuesto) en una excepción al iniciar el servidor:
la excepción anidada es org.springframework.beans.factory.NoSuchBeanDefinitionException: no se ha definido un bean único de tipo [com.sevenp.mobile.samplemgmt.service.dao.DeviceDao]: bean coincidente único esperado pero encontrado 2: [deviceDao, jdbcDeviceDao]
de una clase que intenta conectar automáticamente el bean así
@Autowired
private DeviceDao hibernateDevicDao;
porque hay dos beans que implementan la misma interfaz.
La pregunta:
¿Es posible configurar los beans para que
1. No tengo que hacer cambios en las clases existentes, que ya tienen el HibernateDeviceDaoautowired
2. todavía poder usar el segundo (nuevo) bean como este:
@Autowired
@Qualifier("jdbcDeviceDao")
Es decir, necesitaría una forma de configurar el HibernateDeviceDaobean como el bean predeterminado que se conectará automáticamente, permitiendo simultáneamente el uso de un JdbcDeviceDaocuando se especifique explícitamente con la @Qualifieranotación.
Lo que ya he probado:
Traté de configurar la propiedad
autowire-candidate="false"
en la configuración de bean para JdbcDeviceDao:
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
<property name="dataSource" ref="jdbcDataSource"/>
</bean>
porque la documentación de Spring dice que
Indica si este bean debe considerarse o no cuando se buscan candidatos coincidentes para satisfacer los requisitos de cableado automático de otro bean. Tenga en cuenta que esto no afecta a las referencias explícitas por nombre, que se resolverán incluso si el bean especificado no está marcado como candidato de cableado automático. *
lo cual interpreté para significar que aún podía conectar automáticamente JdbcDeviceDaousando la @Qualifieranotación y tener el HibernateDeviceDaobean predeterminado. Aparentemente, mi interpretación no fue correcta, ya que esto da como resultado el siguiente mensaje de error al iniciar el servidor:
Dependencia insatisfecha del tipo [clase com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceDao]: esperaba al menos 1 bean coincidente
viniendo de la clase donde probé el cableado automático del bean con un calificador:
@Autowired
@Qualifier("jdbcDeviceDao")
Solución:
La sugerencia de skaffman de probar la anotación @Resource funcionó. Entonces, la configuración tiene autowire-candidato establecido en false para jdbcDeviceDao y cuando uso el jdbcDeviceDao me refiero a él usando la anotación @Resource (en lugar de @Qualifier):
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
fuente

Respuestas:
Yo sugeriría que marca la clase Hibernate DAO con
@Primary, es decir, (suponiendo que utilizó@RepositoryenHibernateDeviceDao):De esta manera, se seleccionará como el candididate de cableado automático predeterminado, sin necesidad
autowire-candidatedel otro bean.Además, en lugar de usar
@Autowired @Qualifier, me parece más elegante usar@Resourcepara recoger frijoles específicos, es decirfuente
@Resourceanotación, como también sugerí.@Resourcey@Qualifier, aparte del hecho de que el primero es relativamente más nuevo que el segundo?¿Qué hay de
@Primary?O si desea que su versión Jdbc se use por defecto:
@PrimaryTambién es ideal para las pruebas de integración cuando puede reemplazar fácilmente el bean de producción con la versión tropezada al anotarlo.fuente
primary=""atributo estaba disponible antes. Simplemente declareHibernateDeviceDaoen XML y excluya del escaneo de componentes / anotaciones.Para Spring 2.5, no hay
@Primary. La única forma es usar@Qualifier.fuente
fuente
La razón por la cual @Resource (name = "{your child class name}") funciona pero @Autowired a veces no funciona es por la diferencia de su secuencia de correspondencia
Secuencia coincidente de @Autowire
Type, Qualifier, Name
Secuencia coincidente de @Resource
Nombre, Tipo, Calificador
La explicación más detallada se puede encontrar aquí:
Inyectar y Recurso y anotaciones con conexión automática
En este caso, una clase secundaria diferente heredada de la clase o interfaz principal confunde @Autowire, porque son del mismo tipo; Como @Resource usa Name como primera prioridad coincidente, funciona.
fuente