Aynı arabirimi uygulayan iki fasulyenin otomatik kablolaması - varsayılan fasulyeyi autowire olarak nasıl ayarlayabilirim?


138

Arka fon:

Spring 2.5 / Java / Tomcat uygulamam var. Birçok yerde uygulama boyunca kullanılan aşağıdaki fasulye vardır

public class HibernateDeviceDao implements DeviceDao

ve yeni olan aşağıdaki fasulye:

public class JdbcDeviceDao implements DeviceDao

İlk fasulye yapılandırıldı (paketteki tüm fasulye dahil)

<context:component-scan base-package="com.initech.service.dao.hibernate" />

İkinci (yeni) fasulye ayrı olarak yapılandırılır

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao">
    <property name="dataSource" ref="jdbcDataSource">
</bean>

Bu, sunucuyu başlatırken (elbette) bir istisna oluşturur:

yuvalanmış istisna org.springframework.beans.factory.NoSuchBeanDefinitionException: Tek bir fasulye türü [com.sevenp.mobile.samplemgmt.service.dao.Devicedao] tanımlandı: beklenen tek eşleşen fasulye ama 2 bulundu: [devicedao, jdbcDevicedao]

fasulyeyi böyle otomatik olarak bağlamaya çalışan bir sınıftan

@Autowired
private DeviceDao hibernateDevicDao;

çünkü aynı arayüzü uygulayan iki tane fasulye var.

Soru:

Fasulyeleri şu şekilde yapılandırmak mümkün mü?

1. Halihazırda otomatik HibernateDeviceDaokablolu olan mevcut sınıflarda değişiklik yapmak zorunda değilim

2. hala ikinci (yeni) fasulyeyi şu şekilde kullanabilmek:

@Autowired
@Qualifier("jdbcDeviceDao")

Yani, HibernateDeviceDaofasulyeyi otomatik olarak bağlanacak varsayılan fasulye olarak yapılandırmanın bir yoluna ihtiyacım olacaktı , aynı anda açıklamanın ek açıklama JdbcDeviceDaoile belirtildiği zaman kullanılmasına izin vereceğim @Qualifier.

Zaten denedim:

Özelliği ayarlamayı denedim

autowire-candidate="false"

JdbcDevicedao için fasulye konfigürasyonunda:

<bean id="jdbcDeviceDao" class="com.initech.service.dao.jdbc.JdbcDeviceDao" autowire-candidate="false">
    <property name="dataSource" ref="jdbcDataSource"/>
</bean>

çünkü Bahar belgeleri

Başka bir fasulyenin otomatik kablolama gereksinimlerini karşılamak için eşleşen adaylar ararken bu fasulyenin dikkate alınıp alınmayacağını belirtir. Bunun, belirtilen fasulye otomatik tel adayı olarak işaretlenmemiş olsa bile çözümlenecek ada göre açık referansları etkilemediğini unutmayın. *

ki JdbcDeviceDaobu @Qualifieraçıklamayı kullanarak autowire yapabileceğimi ve HibernateDeviceDaovarsayılan fasulye olarak kullanabileceğimi ifade ettim . Görünüşe göre benim yorumum doğru değildi, çünkü bu sunucuyu başlatırken aşağıdaki hata mesajıyla sonuçlanır:

[Class com.sevenp.mobile.samplemgmt.service.dao.jdbc.JdbcDevicedao] türünün tatminsiz bağımlılığı: en az 1 eşleşen fasulye bekleniyor

fasulye bir niteleyici ile otomatik kablolama denedim sınıftan geliyor:

@Autowired
@Qualifier("jdbcDeviceDao")

Çözüm:

skaffman'ın @Resource ek açıklamasını deneme önerisi çalıştı. Yani yapılandırma autowire-aday jdbcDevicedao için false olarak ayarlanmış ve jdbcDevicedao kullanırken @Resource ek açıklamasını (@Qualifier yerine) kullanarak başvuruyorum:

@Resource(name = "jdbcDeviceDao")
private JdbcDeviceListItemDao jdbcDeviceDao;

Kodda 100 yerde bu arayüzü kullanırsanız ve ben başka bir uygulamaya geçmek istiyorum her yerde niteleyici veya kaynak ek açıklamaları değiştirmek istemiyorum. Ayrıca her iki uygulamanın kodunu değiştirmek istemiyorum. Neden Guice'de olduğu gibi açık bağlayıcı olasılıklar yok?
Daniel Hári

Yanıtlar:


134

Birlikte hazırda DAO sınıfını işaretleme öneririm @Primary, yani (kullandığınız varsayarak @Repositoryüzerinde HibernateDeviceDao):

@Primary
@Repository
public class HibernateDeviceDao implements DeviceDao

Bu şekilde autowire-candidate, diğer fasülyeye gerek kalmadan varsayılan otomatik telli candididat olarak seçilecektir .

Ayrıca, kullanmak yerine @Autowired @Qualifier, @Resourcebelirli fasulye toplamak için kullanmanın daha zarif olduğunu düşünüyorum , yani

@Resource(name="jdbcDeviceDao")
DeviceDao deviceDao;

Bahar 2.5 (şimdi soruyu düzenledim) kullandığım soruda bahsetmeyi unuttum, bu yüzden @ Primer bir seçenek değil.
simon

1
@simon: Evet, bu oldukça önemliydi. @ResourceÖnerdiğim gibi ek açıklamayı deneyin .
skaffman

1
Teşekkürler, kaynak notu sorunu çözdü - şimdi autowire-aday özellik beklediğim gibi çalışıyor.
simon

Teşekkürler! Aracılığıyla fasulye adını belirtirken arasındaki fark nedir @Resourceve @Qualifierbirbirinden eski ikincisi görece daha yeni olmasından,?
15'de

1
@asgs Kaynak ek açıklamasını kullanmak işleri basitleştirir. Otomatik kablolu / niteleyici kombinasyonuna sahip olmak yerine, bağımlılık enjeksiyonu için işaretleyebilir ve adı bir satırda belirtebilirsiniz. Simon'un çözümünün gereksiz olduğunu, otomatik kablolu ek açıklamanın kaldırılabileceğini unutmayın.
Gilbert Arenas Hançer

37

Ne olmuş @Primary?

Birden fazla adayın tek değerli bir bağımlılığı otomatik olarak bağlamak için nitelikli olduğu zaman bir fasülye tercih verilmesi gerektiğini belirtir . Adaylar arasında tam olarak bir 'birincil' fasulye varsa, otomatik kablolu değer olacaktır. Bu ek açıklama anlamsal olarak <bean>öğenin primaryBahar XML'deki özelliğine eşdeğerdir .

@Primary
public class HibernateDeviceDao implements DeviceDao

Veya Jdbc sürümünüzün varsayılan olarak kullanılmasını istiyorsanız:

<bean id="jdbcDeviceDao" primary="true" class="com.initech.service.dao.jdbc.JdbcDeviceDao">

@Primary ayrıca, üretim fasulyesini ek açıklama ile stubbed sürümüyle kolayca değiştirebileceğiniz entegrasyon testi için mükemmeldir.


Bahar 2.5 (şimdi soruyu düzenledim) kullandığım soruda bahsetmeyi unuttum, bu yüzden @ Primer bir seçenek değil.
simon

1
@simon: primary=""Özelliğin daha önce mevcut olduğuna inanıyorum . HibernateDeviceDaoXML olarak beyan edin ve bileşen / ek açıklama taramasından hariç tutun.
Tomasz Nurkiewicz

1
3.0'dan beri mevcut olan belgelere göre: static.springsource.org/spring/docs/3.1.x/javadoc-api/org/… Neyse ki, mümkün olduğunda bir sonraki proje için Birincil notu hatırlayacağım 3.x nasıl kullanılır
simon

8

İlkbahar 2.5 için, hayır @Primary. Tek yol kullanmaktır @Qualifier.


2
The use of @Qualifier will solve the issue.
Explained as below example : 
public interface PersonType {} // MasterInterface

@Component(value="1.2") 
public class Person implements  PersonType { //Bean implementing the interface
@Qualifier("1.2")
    public void setPerson(PersonType person) {
        this.person = person;
    }
}

@Component(value="1.5")
public class NewPerson implements  PersonType { 
@Qualifier("1.5")
    public void setNewPerson(PersonType newPerson) {
        this.newPerson = newPerson;
    }
}

Now get the application context object in any component class :

Object obj= BeanFactoryAnnotationUtils.qualifiedBeanOfType((ctx).getAutowireCapableBeanFactory(), PersonType.class, type);//type is the qualifier id

you can the object of class of which qualifier id is passed.

0

@Resource (name = "{çocuğunuzun sınıf adı}") neden çalıştığını ancak @Autowired'ın bazen çalışmadığının nedeni, Eşleştirme dizilerinin farkıdır

@Otomatik Aktarma
Türü, Niteleyici, Ad ile eşleşen sıralama

@Kaynak
Adı, Türü, Niteleyicinin eşleşen dizisi

Daha ayrıntılı açıklama burada bulunabilir:
Enjeksiyon ve Kaynak ve Otomatik Kablolu ek açıklamalar

Bu durumda, üst sınıftan veya arabirimden miras alınan farklı alt sınıflar @Autowire'ı karıştırır, çünkü bunlar aynı türdendir; @Kaynak, ilk eşleşen öncelik olarak Adı kullandığından, çalışır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.