İlkbaharda otomatik kablolama nasıl çalışır?


510

Control ( IoC) inversiyonunun nasıl çalıştığı konusunda biraz kafam karıştı Spring.

Diyelim ki arayüzü UserServiceImpluygulayan bir servis sınıfım var UserService.

Bu nasıl olurdu @Autowired?

Ve benim, Controllersnasıl olur ben instantiatebir instancebu hizmetin?

Sadece aşağıdakileri yapabilir miyim?

UserService userService = new UserServiceImpl();

Yanıtlar:


703

İlk ve en önemlisi - tüm Bahar fasulyeleri yönetilir - "uygulama bağlamı" adı verilen bir kabın içinde "yaşar".

İkinci olarak, her uygulamanın bu bağlama bir giriş noktası vardır. Web uygulamaları bir Servlet'e sahiptir, JSF bir el çözümleyici kullanır, vb. Ayrıca, uygulama bağlamının önyükleme yapıldığı ve tüm fasulye - otomatik kablolu olduğu bir yer vardır. Web uygulamalarında bu bir başlangıç ​​dinleyicisi olabilir.

Otomatik kablolama, bir çekirdeğin bir örneğini başka bir çekirdeğin bir örneğinde istenen alana yerleştirerek olur. Her iki sınıf da fasulye olmalı, yani uygulama bağlamında yaşayacakları şekilde tanımlanmalıdır.

Uygulama bağlamında "yaşamak" nedir? Bu, bağlamın nesneleri değil, nesneleri somutlaştırdığı anlamına gelir . Yani - asla yapmazsınız - new UserServiceImpl()kap her enjeksiyon noktasını bulur ve orada bir örnek oluşturur.

Denetleyicilerinizde aşağıdakilere sahipsiniz:

@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {

    // Tells the application context to inject an instance of UserService here
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public void login(@RequestParam("username") String username,
           @RequestParam("password") String password) {

        // The UserServiceImpl is already injected and you can use it
        userService.login(username, password);

    }
}

Birkaç not:

  • Gözlerinde farklı applicationContext.xmletkinleştirmek gerektiğini <context:component-scan>sınıflar için taranır, böylece @Controller, @Servicevb ek açıklamalar.
  • Bir Spring-MVC uygulaması için giriş noktası DispatcherServlet'tir, ancak sizden gizlenir ve dolayısıyla uygulama bağlamının doğrudan etkileşimi ve önyüklemesi sahnenin arkasında gerçekleşir.
  • UserServiceImplek açıklama kullanarak <bean id=".." class="..">veya kullanarak fasulye olarak da tanımlanmalıdır @Service. Tek uygulayıcısı UserServiceolacağından enjekte edilecektir.
  • @AutowiredEk açıklama dışında , Spring XML ile yapılandırılabilir otomatik kablolama kullanabilir. Bu durumda, varolan bir fasulye ile eşleşen bir ada veya türe sahip olan tüm alanlara otomatik olarak bir fasulye enjekte edilir. Aslında, bu otomatik kablolamanın ilk fikriydi - herhangi bir konfigürasyon olmadan bağımlılıklara enjekte edilen alanlara sahip olmak. Diğer ek açıklamalar gibi @Inject, @Resourceaynı zamanda kullanılabilir.

7
evet UserServiceImpl Servisi açıklamalı edilir ve UserService arayüzü
Bozho

16
varsayılan kapsam singleton'dur, bu nedenle birden çok yere enjekte edilen fasulyenin yalnızca bir örneğine sahip olursunuz. Kapsamı "prototip" olarak açıkça tanımlarsanız, muhtemelen tembel olan (yapılandırmaya bağlı olarak) birden fazla örnek olacaktır
Bozho

2
Gönderiniz için çok teşekkürler, gerçekten benim için işleri temizledi. 'Tek uygulayıcı veya UserService olacağından enjekte edilecektir.' - Kullanıcı Hizmetini uygulayan birden fazla sınıf varsa? Spring hangi uygulamayı kullanması gerektiğini nasıl biliyor?
Shishigami

7
"birincil" olarak adlandırılan biri varsa onu kullanır. Aksi takdirde bir istisna atar
Bozho

3
hayır, userService yalnızca bir kez oluşturulur, tekil kapsamdadır
Bozho

64

Ek açıklama yolunu mu yoksa çekirdek XML tanım yolunu mu istediğinize bağlıdır.

Diyelim ki fasulyeniz sizin için tanımlandı applicationContext.xml:

<beans ...>

    <bean id="userService" class="com.foo.UserServiceImpl"/>

    <bean id="fooController" class="com.foo.FooController"/>

</beans>

Otomatik kablolama, uygulama başlatıldığında gerçekleşir. Yani, fooControllerhangi argümanlar için UserServiceImplsınıfı kullanmak isterse , ona aşağıdaki gibi açıklama eklersiniz:

public class FooController {

    // You could also annotate the setUserService method instead of this
    @Autowired
    private UserService userService;

    // rest of class goes here
}

Gördüğünde @Autowired, Spring, içindeki özelliğe uyan bir sınıfı arayacak applicationContextve otomatik olarak enjekte edecektir. Birden fazla UserServicefasulyeniz varsa, hangisini kullanması gerektiğini belirtmeniz gerekir.

Aşağıdakileri yaparsanız:

UserService service = new UserServiceImpl();

@AutowiredKendiniz ayarlamadığınız sürece almaz .


2
Yani tanımlayan kullanımı nedir bean idiçinde applicationContext.xml. userServiceDeğişkeni UserServicetür ile tanımlamamız gerekecek . Neden xmldosyaya giriş yapalım .
engerek

20

@Autowired İlkbahar 2.5'te sunulan bir ek açıklamadır ve yalnızca enjeksiyon için kullanılır.

Örneğin:

class A {

    private int id;

    // With setter and getter method
}

class B {

    private String name;

    @Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
    A a;

    // With setter and getter method

    public void showDetail() {
        System.out.println("Value of id form A class" + a.getId(););
    }
}

10
Bu derlenmez ve genellikle yanlıştır. @Autowired" Bsınıftaki tüm işlevi (yöntemi) ve değişkeni sınıftan kullanabilirsiniz" anlamına gelmez A. Ne yapar bir örneğini getiriyor Aörneklerini içine B, bu yüzden yapabileceğiniz a.getId()dan B.
Dmitry Minkovsky

@dimadima Yani eğer System.out.println ("id form A sınıfı sınıfı" + a.getId ()); yaparsa ve aslında yaptığı gibi daha doğru olur. Lütfen cevap verin, çünkü bu benim için sezgisel olarak açık ve mevcut anlayış seviyemize göre Otomatik Kablolamayı açıklıyor.
John Doe

otomatik kablolu ek açıklama, ilkbaharda 2.5 dokümanlar.spring.io/
docs/

1
Bu konuda yeni olduğum için daha iyi anlaşılması için, @autowired, varsayılan kurucuyu kullanarak A Sınıfını başlatır mı? Aksi takdirde, otomatik kablolu kullanırsak değerlerin bir fasulye veya serviste nasıl somutlaştırılacağı belirlenir. Sanırım varsayılan yapıcı çağırırsa, neden ilk etapta otomatik kablolama kullanın, sadece A a = yeni A (). Lütfen açıkla?
Sameer

@Sameer Otomatik kablolama bağımlılıkları ile Birim Testlerinizde ve Denetleyici, Servis ve Dao Sınıflarında çok sayıda kazan plakası kaydedebilirsiniz, çünkü alanların somutlaştırılması otomatik olarak beraberinde gelir. Yapıcıyı aramaya gerek yok.
kiltek

9

@AutowiredDahili olarak nasıl çalışır?

Misal:

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xml dosyası kullanılmıyorsa benzer görünecektir @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

Kullanıyorsanız @Autowiredo zaman:

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xml dosyası kullanılmıyorsa benzer görünecektir @Autowired:

<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

Hala bir şüpheniz varsa, aşağıda canlı demoyu izleyin

@Autowired dahili olarak nasıl çalışır?


6

Hizmet sınıfınıza UserServiceImplek açıklama eklemeniz yeterlidir :

@Service("userService")

Bahar konteyneri, hizmet olarak kaydedildiği için bu sınıfın yaşam döngüsüyle ilgilenecektir.

Daha sonra kumandanızda otomatik olarak kablolayabilir (örnekleyebilir) ve işlevselliğini kullanabilirsiniz:

@Autowired
UserService userService;

3

Yay bağımlılığı enjeksiyonu, sınıfınızdan kuplajı kaldırmanıza yardımcı olur. Bunun gibi bir nesne oluşturmak yerine:

UserService userService = new UserServiceImpl();

DI'yi tanıttıktan sonra bunu kullanacaksınız:

@Autowired
private UserService userService;

Bunu başarmak için, dosyanızda bir hizmet fasulyesi oluşturmanız gerekir ServiceConfiguration. Bundan sonra, bu fasulyeyi ServiceConfigurationsınıfınıza almanız gerekir, WebApplicationConfigurationböylece bu fasulyeyi Kontrolörünüze otomatik olarak bağlayabilirsiniz:

public class AccController {

    @Autowired
    private UserService userService;
} 

Burada bir java yapılandırma tabanlı POC bulabilirsiniz örnek .


1

Standart yolu:

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

Kullanıcı servis arayüzü:

public interface UserService {
    String print(String text);
}

UserServiceImpl sınıfı:

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

Çıktı: Example test UserServiceImpl

Bu sıkı birleştirilmiş sınıfların, kötü tasarım örneklerinin harika bir örneğidir ve test ile ilgili bir sorun olacaktır (PowerMockito da kötüdür).

Şimdi SpringBoot bağımlılık enjeksiyonuna bir göz atalım, gevşek bağlantıya güzel bir örnek:

Arayüz aynı kalır,

Ana sınıf:

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImpl sınıfı:

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

Çıktı: Example test UserServiceImpl

ve şimdi testi yazmak kolaydır:

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

Yapıcıya @Autowiredek açıklama gösterdim ancak ayarlayıcı veya sahada da kullanılabilir.


0

Kontrolün ters çevrilmesi konsepti, nesneleri manuel olarak başlatmak ve gerekli tüm bağımlılıkları sağlamak için bir angaryadan özgür olduğunuz anlamına gelir. Sınıfa uygun açıklama ekleyerek açıklama eklediğinizde (örn. @Service) Spring nesneyi sizin için otomatik olarak başlatır. Ek açıklamalara aşina değilseniz, bunun yerine XML dosyasını da kullanabilirsiniz. Ancak, newtüm yay içeriğini yüklemek istemediğinizde, birim testlerinde sınıfları manuel olarak ( anahtar kelimeyle) başlatmak kötü bir fikir değildir.


0

Yay yapılandırma dosyasına @Autowiredöğe ekleyerek ek açıklamayı etkinleştirmeniz gerektiğini unutmayın <context:annotation-config/>. Bu AutowiredAnnotationBeanPostProcessor, ek açıklamanın işlenmesine dikkat edenleri kaydedecektir .

Ardından, saha enjeksiyon yöntemini kullanarak hizmetinizi otomatik olarak bağlayabilirsiniz.

public class YourController{

 @Autowired
 private UserService userService; 

}

Bunu Spring @autowired ek açıklamasından buldum


0

Kullanarak bir örnek oluşturmanın 3 yolu vardır @Autowired.

1. @AutowiredÖzellikler üzerinde

Ek açıklama doğrudan mülklerde kullanılabilir, bu nedenle alıcılar ve ayarlayıcılara olan ihtiyacı ortadan kaldırır:

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

Yukarıdaki örnekte, Bahar arar ve enjekte eder userServicezaman UserControlleroluşturulur.

2. @AutowiredSetters üzerinde

@AutowiredEk açıklama ayarlayıcı yöntemleri kullanılabilir. Aşağıdaki örnekte, ek açıklama setter yönteminde kullanıldığında, setter yöntemi, oluşturulduğu userServicezaman örneğiyle çağrılır UserController:

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
            this.userService = userService;
    }
}

3. @AutowiredYapıcılar hakkında

@AutowiredAçıklama da kurucular üzerinde kullanılabilir. Aşağıdaki örnekte, açıklama bir kurucuda kullanıldığında , oluşturulduğunda userServiceyapıcıya argüman olarak bir örneği enjekte edilir UserController:

public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService= userService;
    }
}

0

Basit bir deyişle, Otomatik kablolama, bağlantıları otomatik olarak kablolama, şimdi bunu kimin yaptığı ve ne tür bir kablolama olduğu sorusu geliyor. Cevap: Konteyner bunu yapar ve İkincil kablolama türü desteklenir, ilkellerin manuel olarak yapılması gerekir.

Soru: Konteyner ne tür kablolamayı biliyor?

Cevap: Biz byType, byName, yapıcı olarak tanımlıyoruz.

Soru: Otomatik kablolama tipini tanımlamadığımız bir yol var mı?

Cevap: Evet, orada bir ek açıklama yaparak, @Autowired.

Soru: Ama sistem nasıl biliyor, bu tür ikincil verileri seçmem gerekiyor?

Cevap: Bu verileri size spring.xml dosyasında veya sınıfınıza sterotip ek açıklamaları kullanarak sunacaksınız, böylece kap kendiniz için nesneleri oluşturabilir.

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.