Autowiring two beans implementando la misma interfaz - ¿cómo establecer por defecto bean a autowire?
Antecedentes:
Tengo una aplicación Spring 2.5/Java/Tomcat. Hay el siguiente frijol, que se utiliza a lo largo de la aplicación en muchos lugares
public class HibernateDeviceDao implements DeviceDao
Y el siguiente frijol que es nuevo:
public class JdbcDeviceDao implements DeviceDao
El primer frijol está configurado de manera (todos los frijoles en el paquete están incluidos)
<context:component-scan base-package="com.initech.service.dao.hibernate" />
El segundo (nuevo) frijol 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:
Anidado la excepción es org.springframework.frijol.fábrica.NoSuchBeanDefinitionException: No hay frijol único de tipo [com.sevenp.móvil.samplemgmt.Servicio.dao.DeviceDao] se define: se espera un solo frijol coincidente pero se encontró 2: [deviceDao, jdbcDeviceDao]
De una clase tratando de autowire el frijol como este
@Autowired
private DeviceDao hibernateDevicDao;
Porque hay dos beans implementando la misma interfaz.
La pregunta:
¿Es posible configurar los frijoles de modo que
1. No tengo que hacer cambios a las clases existentes, que ya tienen el HibernateDeviceDao
autowired
2. aún siendo capaz de usar el segundo (nuevo) frijol de esta manera:
@Autowired
@Qualifier("jdbcDeviceDao")
Es decir, necesitaría una forma de configurar el frijol HibernateDeviceDao
como el frijol por defecto para ser autocableado, permitiendo simultáneamente el uso de un JdbcDeviceDao
cuando se especifique explícitamente con la anotación @Qualifier
.
Lo que ya he intentado:{[18]]}
Traté de establecer 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 frijol debe ser considerado o no cuando buscando candidatos coincidentes para satisfacer a otro frijol requisitos de autowiring. Tenga en cuenta que esto no afecta explícitamente referencias por nombre, que se resolverán incluso si el especificado bean no está marcado como autowire candidato.*
Que interpreté para significar que todavía podría autowire JdbcDeviceDao
usando la anotación @Qualifier
y tener el HibernateDeviceDao
como frijol por defecto. Sin embargo, aparentemente mi interpretación no fue correcta, ya que esto resulta en el siguiente mensaje de error al iniciar el servidor:
Dependencia insatisfecha del tipo [clase com.sevenp.móvil.samplemgmt.Servicio.dao.jdbc.JdbcDeviceDao]: se espera que al menos 1 haba coincidente
Viniendo de la clase donde He intentado autowiring el frijol con un calificador:
@Autowired
@Qualifier("jdbcDeviceDao")
Solución:
Skaffman's sugerencia para probar la anotación @Resource funcionó. Así que la configuración tiene autowire-candidate establecido en false para jdbcDeviceDao y cuando se utiliza el jdbcDeviceDao me refiero a ella utilizando la anotación @Resource (en lugar de @Qualifier):
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
3 answers
Yo sugeriría marcar la clase de Hibernación DAO con @Primary
, es decir (asumiendo que usaste @Repository
en HibernateDeviceDao
):
@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao
De esta manera se seleccionará como el candidato de autowire predeterminado, sin necesidad de autowire-candidate
en el otro bean.
También, en lugar de usar @Autowired @Qualifier
, me parece más elegante usar @Resource
para recoger frijoles específicos, es decir,
@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 12:35:52
¿Qué pasa con @Primary
?
Indica que a un bean se le debe dar preferencia cuando múltiples candidatos están calificados para autowire una dependencia de un solo valor. Si existe exactamente un frijol 'primario' entre los candidatos, será el valor autowired. Esta anotación es semánticamente equivalente al atributo
<bean>
del elementoprimary
en Spring XML.
@Primary
public class HibernateDeviceDao implements DeviceDao
O si desea que su versión Jdbc se use de forma predeterminada:
<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
@Primary
es también ideal para pruebas de integración cuando puede reemplazar fácilmente production bean con la versión stubbed anotándola.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-10 12:37:01
Para la primavera 2.5, no hay @Primary
. La única manera es usar @Qualifier
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-24 14:03:25