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 HibernateDeviceDao
autowired
2. todavía poder usar el segundo (nuevo) bean como este:
@Autowired
@Qualifier("jdbcDeviceDao")
Es decir, necesitaría una forma de configurar el HibernateDeviceDao
bean como el bean predeterminado que se conectará automáticamente, permitiendo simultáneamente el uso de un JdbcDeviceDao
cuando se especifique explícitamente con la @Qualifier
anotació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 JdbcDeviceDao
usando la @Qualifier
anotación y tener el HibernateDeviceDao
bean 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ó@Repository
enHibernateDeviceDao
):De esta manera, se seleccionará como el candididate de cableado automático predeterminado, sin necesidad
autowire-candidate
del otro bean.Además, en lugar de usar
@Autowired @Qualifier
, me parece más elegante usar@Resource
para recoger frijoles específicos, es decirfuente
@Resource
anotación, como también sugerí.@Resource
y@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:
@Primary
Tambié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 declareHibernateDeviceDao
en 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