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;
Author: Kronen, 2012-05-10

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;
 111
Author: skaffman,
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 elemento primary 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.

 30
Author: Tomasz Nurkiewicz,
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.

 7
Author: blang,
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