Tło:
Mam aplikację Spring 2.5 / Java / Tomcat. Oto następująca fasola, która jest używana w wielu miejscach w aplikacji
public class HibernateDeviceDao implements DeviceDao
oraz następujące ziarna, które są nowe:
public class JdbcDeviceDao implements DeviceDao
Pierwsza fasola jest skonfigurowana w ten sposób (wszystkie ziarna w pakiecie są uwzględnione)
<context:component-scan base-package="com.initech.service.dao.hibernate" />
Drugie (nowe) ziarno jest konfigurowane osobno
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
<property name="dataSource" ref="jdbcDataSource">
</bean>
Powoduje to (oczywiście) wyjątek podczas uruchamiania serwera:
Wyjątek zagnieżdżony to org.springframework.beans.factory.NoSuchBeanDefinitionException: Nie zdefiniowano żadnego unikalnego komponentu bean typu [com.sevenp.mobile.samplemgmt.service.dao.DeviceENAULT]: spodziewano się pojedynczego pasującego komponentu bean, ale znaleziono 2: [device replace, jdbcDeviceBIZ]
z klasy próbującej autopowielać fasolę w ten sposób
@Autowired
private DeviceDao hibernateDevicDao;
ponieważ istnieją dwie fasole implementujące ten sam interfejs.
Pytanie:
Czy można tak skonfigurować ziarna?
1. Nie muszę wprowadzać zmian w istniejących klasach, które mają już HibernateDeviceDao
autowired
2. nadal można używać drugiej (nowej) fasoli w następujący sposób:
@Autowired
@Qualifier("jdbcDeviceDao")
Tzn. HibernateDeviceDao
Potrzebowałbym sposobu na skonfigurowanie komponentu bean jako domyślnego komponentu bean do autowiredowania, jednocześnie umożliwiając użycie a, JdbcDeviceDao
gdy wyraźnie to określono w @Qualifier
adnotacji.
Czego już próbowałem:
Próbowałem ustawić nieruchomość
autowire-candidate="false"
w konfiguracji bean dla JdbcDevice_action:
<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
<property name="dataSource" ref="jdbcDataSource"/>
</bean>
ponieważ dokumentacja Spring tak mówi
Wskazuje, czy to ziarno powinno być brane pod uwagę podczas wyszukiwania pasujących kandydatów, aby spełnić wymagania dotyczące automatycznego podłączenia innego ziarna. Należy pamiętać, że nie ma to wpływu na jawne odwołania według nazwy, które zostaną rozwiązane, nawet jeśli określony komponent bean nie zostanie oznaczony jako kandydat na autowire. *
co zinterpretowałem jako oznaczające, że nadal mogę autopowire JdbcDeviceDao
przy użyciu @Qualifier
adnotacji i mieć HibernateDeviceDao
jako domyślną fasolę. Najwyraźniej moja interpretacja nie była jednak poprawna, ponieważ powoduje to następujący komunikat o błędzie podczas uruchamiania serwera:
Niezadowalająca zależność typu [klasa com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDeviceENAULT]: oczekiwano co najmniej 1 pasującego komponentu bean
pochodzący z klasy, w której próbowałem automatycznie podłączyć fasolę z kwalifikatorem:
@Autowired
@Qualifier("jdbcDeviceDao")
Rozwiązanie:
Sugestia skaffmana, aby wypróbować adnotację @Resource, zadziałała. W związku z tym konfiguracja ma ustawioną wartość „false” dla opcji autowire-kandydat dla jdbcDevice_action i podczas korzystania z jdbcDevice zamiar odwołuję się do niej za pomocą adnotacji @Resource (zamiast @Qualifier):
@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;
źródło
Odpowiedzi:
Sugeruję oznaczenie klasy DAO z Hibernate
@Primary
, czyli (zakładając, że stosowane@Repository
naHibernateDeviceDao
):W ten sposób zostanie wybrany jako domyślny kandydat na autoprzewód, bez potrzeby
autowire-candidate
na drugim ziarnie .Poza tym, zamiast używać
@Autowired @Qualifier
, uważam, że bardziej eleganckie jest używanie go@Resource
do zbierania określonych ziaren, tjźródło
@Resource
adnotację, jak również zasugerowałem.@Resource
a@Qualifier
, poza tym, że ta pierwsza jest stosunkowo nowsza od drugiej?O co chodzi
@Primary
?Lub jeśli chcesz, aby Twoja wersja Jdbc była używana domyślnie:
@Primary
jest również świetny do testowania integracji, kiedy można łatwo zastąpić komponent bean produkcyjną wersją, dodając do niej adnotacje.źródło
primary=""
atrybut był dostępny wcześniej. Wystarczy zadeklarowaćHibernateDeviceDao
w formacie XML i wykluczyć go ze skanowania komponentów / adnotacji.W przypadku wersji Spring 2.5 nie ma
@Primary
. Jedynym sposobem jest użycie@Qualifier
.źródło
źródło
Powodem, dla którego @Resource (name = „{nazwa Twojej klasy podrzędnej}”) działa, ale @Autowired czasami nie działa, jest różnica w ich kolejności dopasowywania
Pasująca sekwencja @Autowire
Type, Qualifier, Name
Pasująca sekwencja @Resource
Name, Type, Qualifier
Bardziej szczegółowe wyjaśnienie można znaleźć tutaj:
Inject and Resource and Autowired adnotations
W tym przypadku różne klasy potomne dziedziczone z klasy nadrzędnej lub interfejsu dezorientują @Autowire, ponieważ są tego samego typu; Ponieważ @Resource używa nazwy jako pierwszego pasującego priorytetu, działa.
źródło