Baharı Anlama @Otomatik kullanım


309

Spring Autowired ek açıklamasını anlamak için spring 3.0.x referans belgelerini okuyorum:

3.9.2 @ Otomatik ve @Inject

Aşağıdaki örnekleri anlayamıyorum. Çalışması için XML'de bir şey yapmamız gerekiyor mu?

ÖRNEK 1

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

ÖRNEK 2

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(MovieCatalog movieCatalog,
                    CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

İki sınıf aynı arabirimi uygulayarak ve aynı sınıfı kullanarak nasıl otomatik olarak bağlanabilir?

Misal:

class Red implements Color
class Blue implements Color

class myMainClass{
    @Autowired 
    private Color color;

    draw(){
        color.design(); 
    } 
}

Hangi tasarım yöntemi denecek? Red sınıfının tasarım yönteminin Blue değil çağrılmasını nasıl sağlayabilirim?

Yanıtlar:


542

TL; DR

@Autowired ek açıklaması, kabloları XML dosyasında (veya başka bir yolla) kendiniz yapmanız gerektiğini saklar ve sadece sizin için neyin enjekte edilmesi gerektiğini bulur ve bunu sizin için yapar.

Tam açıklama

@AutowiredEk açıklama başka bir yerde enjekte etmek ne yapılandırmaları atlamak için izin verir ve sadece sizin için yapıyor. Paketinizin com.mycompany.moviesbu etiketi XML'inize (uygulama bağlam dosyası) koymanız gerektiğini varsayarsak :

<context:component-scan base-package="com.mycompany.movies" />

Bu etiket otomatik tarama yapar. Fasulye haline gelmesi gereken her sınıfın @Component(basit fasulye için) veya @Controller(bir sunucu uygulaması kontrolü için) veya @Repository( DAOsınıflar için ) gibi doğru bir açıklama ile açıklandığı ve bu sınıfların paketin altında bir yerde olduğunu varsayarsak com.mycompany.movies, Bahar bunların hepsini bulacaktır ve her biri için bir fasulye. Bu, sınıfların 2 taramasında yapılır - ilk kez sadece fasulye olması gereken sınıfları arar ve yapması gereken enjeksiyonları eşleştirir ve ikinci taramada çekirdekleri enjekte eder. Tabii ki, çekirdeklerinizi daha geleneksel XML dosyasında veya bir @Configuration sınıfında (veya üçünün herhangi bir kombinasyonunda) tanımlayabilirsiniz .

@AutowiredBir enjeksiyon gerçekleşmesi gereken yerde açıklama Bahar söyler. Bir yönteme koyarsanız , bir fasulyenin enjekte edilmesi setMovieFindergerektiğini anlar (önek set+ @Autowiredek açıklama ile). İkinci taramada, Spring bir fasulye türünü arar MovieFinderve eğer böyle bir fasulye bulursa onu bu yönteme enjekte eder. Böyle iki fasulye bulursa, bir alacaksınız Exception. Bundan kaçınmak için Exception, @Qualifieraçıklamayı kullanabilir ve iki fasulyeden hangisinin aşağıdaki şekilde enjekte edileceğini söyleyebilirsiniz:

@Qualifier("redBean")
class Red implements Color {
   // Class code here
}

@Qualifier("blueBean")
class Blue implements Color {
   // Class code here
}

Veya XML'inizdeki fasulyeleri bildirmeyi tercih ederseniz, şöyle bir şey olur:

<bean id="redBean" class="com.mycompany.movies.Red"/>

<bean id="blueBean" class="com.mycompany.movies.Blue"/>

In @Autowiredbeyanı, ayrıca eklemeniz gerekir @Qualifierenjekte etmek için iki renk fasulye hangi anlatmak için:

@Autowired
@Qualifier("redBean")
public void setColor(Color color) {
  this.color = color;
}

İki ek açıklama ( @Autowiredve @Qualifier) kullanmak istemiyorsanız @Resource, bu ikisini birleştirmek için kullanabilirsiniz :

@Resource(name="redBean")
public void setColor(Color color) {
  this.color = color;
}

@Resource(Bu yanıtla ilgili ilk yorumunda bu konuda biraz ek verileri okuyabilir) sana iki ek açıklamaları kullanımını yedek ve bunun yerine sadece birini kullanın.

Sadece iki yorum daha ekleyeceğim:

  1. İyi örnek kullanmak olacaktır @Injectyerine @Autowiredo İlkbahar özgü değildir ve çünkü bir parçası JSR-330standardı .
  2. Bir başka iyi uygulama koymak olurdu @Inject/ @Autowiredyerine bir yöntemin bir yapıcı. Bir kurucuya koyarsanız, uygulamayı başlatmaya çalıştığınızda NullPointerExceptionve fasulyeyi gerçekten kullanmanız gerektiğinde kaçındığınızda, enjekte edilen fasulyelerin boş olmadığını ve hızlı bir şekilde başarısız olmadığını doğrulayabilirsiniz .

Güncelleme : Resmi tamamlamak için sınıfla ilgili yeni bir soru oluşturdum @Configuration.


6
Sadece harika cevabınızı tamamlamak için: '@Resource' JSR-250 standardının bir parçasıdır ve basit enjeksiyonun üzerinde ekstra semantiğe sahiptir ('@Autowired' Bahar'dan geldiğini ve '@Inject' JSR-330) :)
Ignacio Rubio

Eğer MovieFinderbir Arayüz ve biz bir fasulye var MovieFinderImpltürüne göre veya adıyla kendisine iğne yapmak (fasulye id = MovieFinder), Bahar irade auto?
Jaskey

@jaskey - kullanıp kullanmadığınıza bağlıdır @Qualifier. Yaparsanız - ada göre, değilse - türe göre. By-type, yalnızca MovieFinderbağlamınızda yalnızca bir tür fasulye varsa çalışır . 1'den fazla bir istisnaya yol açabilir.
Avi

@Avi, Müthiş cevap. Ancak, @Autowiredek açıklamanın Örnek 2'dekiprepare yöntem üzerinde nasıl çalıştığını anlamıyorum . Başlatılıyor, ancak teknik olarak bir ayarlayıcı DEĞİLDİR . MovieRecommender
Karan Chadha

@KaranChadha - Aynı @Autowiredzamanda inşaatçılar için de çalışıyor. Gerekli bağımlılıkları bulur ve bunları kurucuya enjekte eder.
Avi

21

Örnekteki hiçbir şey "aynı arayüzü uygulayan sınıflar" demez. MovieCatalogbir tür ve CustomerPreferenceDaobaşka bir tür. Bahar onları kolayca ayırabilir.

2.x Baharında, fasulyelerin kablolanması çoğunlukla fasulye kimlikleri veya isimleri ile gerçekleşti. Bu hala Bahar 3.x tarafından desteklenmektedir, ancak çoğu zaman, belirli bir türe sahip bir fasulye örneğiniz olacaktır - çoğu hizmet tekiltir. Bunlar için isim oluşturmak sıkıcıdır. Böylece Spring "türüne göre otomatik teli" desteklemeye başladı.

Örneklerin gösterdiği gibi, fasulyeleri tarlalara, yöntemlere ve yapıcılara enjekte etmek için kullanabileceğiniz çeşitli yollar.

XML, her bir çekirdeğin tam nitelikli sınıf adını belirtmeniz gerektiğinden, Spring'in ihtiyaç duyduğu tüm bilgileri zaten içerir. Bununla birlikte, arayüzlere biraz dikkat etmelisiniz:

Bu otomatik kablolama başarısız olacaktır:

 @Autowired
 public void prepare( Interface1 bean1, Interface1 bean2 ) { ... }

Java parametre adlarını bayt kodunda tutmadığından, Spring artık iki fasulye arasında ayrım yapamaz. Düzeltme kullanmaktır @Qualifier:

 @Autowired
 public void prepare( @Qualifier("bean1") Interface1 bean1,
     @Qualifier("bean2")  Interface1 bean2 ) { ... }

@AaronDigulla Çok güzeldi. Ancak işlevi nasıl çağırdığınızı bilmek istiyorum prepare, bu işlevi çağırmak için hangi parametreler kullanılacak?
Nguyen Quang Anh

@NguyenQuangAnh Yöntemi çağırmıyorum, Bean oluşturulduğunda Spring bunu yapacak. Bu, tam olarak @Autowiredalanlar enjekte edildiğinde olur. Bahar daha sonra parametrelere ihtiyaç olduğunu görecek ve parametreleri bulmak için tarla enjeksiyonu için kullanılan kuralları kullanacaktır.
Aaron Digulla

5

Evet, Spring servlet bağlam xml dosyasını fasulyenizi (sınıfları) tanımlayacak şekilde yapılandırabilirsiniz, böylece sizin için otomatik enjeksiyon yapabilir. Bununla birlikte, Spring up'ı çalıştırmak ve çalıştırmak için başka yapılandırmalar yapmanız gerektiğini ve bunu yapmanın en iyi yolunun öğretici bir temel izlemek olduğunu unutmayın.

Eğer Bahar muhtemelen yapılandırılmış sonra, (işe yukarıdaki Örnek 1 için Bahar servlet bağlam xml dosyasında aşağıdakileri yapabilirsiniz lütfen değiştirin paket adını com.movies bu 3. taraf ise doğru paket adı ne olduğu ve sınıfında uygun jar dosyasının sınıf yolunda olduğundan emin olun):

<beans:bean id="movieFinder" class="com.movies.MovieFinder" />

ya da MovieFinder sınıfında ilkel değere sahip bir kurucu varsa, böyle bir şey yapabilirsiniz,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg value="100" />
</beans:bean>

ya da MovieFinder sınıfında başka bir sınıf bekleyen bir kurucu varsa, böyle bir şey yapabilirsiniz,

<beans:bean id="movieFinder" class="com.movies.MovieFinder" >
    <beans:constructor-arg ref="otherBeanRef" />
</beans:bean>

... burada ' otherBeanRef ' beklenen sınıfa gönderme yapan başka bir fasulye.


4
XML'deki tüm kabloları tanımlamak, tüm fikrini kaçırır@Autowired
Avi
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.