Come funziona l'autowiring in primavera?


510

Sono un po 'confuso su come funziona l' inversione di control ( IoC) Spring.

Supponiamo che io abbia una classe di servizio chiamata UserServiceImplche implementa l' UserServiceinterfaccia.

Come sarebbe @Autowired?

E nel mio Controllers, come avrei instantiateun instanceservizio di questo?

Vorrei solo fare quanto segue?

UserService userService = new UserServiceImpl();

Risposte:


703

Innanzitutto, e soprattutto - tutti i bean Spring sono gestiti - "vivono" all'interno di un contenitore, chiamato "contesto dell'applicazione".

In secondo luogo, ogni applicazione ha un punto di accesso a quel contesto. Le applicazioni Web hanno un Servlet, JSF usa un risolutore elettronico , ecc. Inoltre, c'è un posto in cui il contesto dell'applicazione è avviato e tutti i bean sono autowired. Nelle applicazioni Web questo può essere un listener di avvio.

Il collegamento automatico avviene posizionando un'istanza di un bean nel campo desiderato in un'istanza di un altro bean. Entrambe le classi dovrebbero essere bean, ovvero dovrebbero essere definite per vivere nel contesto dell'applicazione.

Cosa significa "vivere" nel contesto dell'applicazione? Ciò significa che il contesto crea un'istanza degli oggetti, non tu. Cioè - non lo fai mai new UserServiceImpl()- il contenitore trova ogni punto di iniezione e imposta un'istanza lì.

Nei controller, hai solo i seguenti:

@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);

    }
}

Alcune note:

  • Nella vostra applicationContext.xmlè necessario attivare il <context:component-scan>modo che le classi vengono analizzati per la @Controller, @Serviceecc annotazioni.
  • Il punto di ingresso per un'applicazione Spring-MVC è DispatcherServlet, ma è nascosto da te, e quindi l'interazione diretta e il bootstrap del contesto dell'applicazione avvengono dietro la scena.
  • UserServiceImpldovrebbe anche essere definito come bean - usando <bean id=".." class="..">o usando l' @Serviceannotazione. Dal momento che sarà l'unico implementatore di UserService, verrà iniettato.
  • Oltre @Autowiredall'annotazione, Spring può utilizzare l'autowiring configurabile in XML. In tal caso, tutti i campi che hanno un nome o un tipo che corrispondono a un bean esistente ottengono automaticamente l'iniezione di un bean. In effetti, questa era l'idea iniziale di autowiring: avere campi iniettati con dipendenze senza alcuna configurazione. Altre annotazioni come @Inject, @Resourcepossono anche essere usate.

7
sì, UserServiceImpl è annotato con Service e UserService è l'interfaccia
Bozho

17
l'ambito predefinito è singleton, quindi avrai solo un'istanza del bean, che viene iniettata in più punti. Se definisci esplicitamente l'ambito come "prototipo", allora saranno presenti più istanze, possibilmente pigre (a seconda della configurazione)
Bozho,

2
Grazie mille per il tuo post, mi ha chiarito davvero le cose. Riguardo a "Poiché sarà l'unico implementatore o UserService, verrà iniettato". - e se ci sono più classi che implementano Userservice? Come fa Spring a sapere quale implementazione dovrebbe usare?
Shishigami,

7
se ce n'è uno designato come "primario", lo usa. Altrimenti genera un'eccezione
Bozho il

3
no, userService viene creato una sola volta, è in ambito singleton
Bozho,

64

Dipende se si desidera il percorso delle annotazioni o il percorso di definizione XML del bean.

Supponiamo che tu abbia definito i bean nel tuo applicationContext.xml:

<beans ...>

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

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

</beans>

L'autowiring si verifica all'avvio dell'applicazione. Quindi, in fooController, che per amor di argomenti vuole usare la UserServiceImplclasse, la annoteresti come segue:

public class FooController {

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

    // rest of class goes here
}

Quando vede @Autowired, Spring cercherà una classe che corrisponde alla proprietà in applicationContexte la inietterà automaticamente. Se hai più di un UserServicebean, dovrai qualificare quale dovrebbe usare.

Se esegui le seguenti operazioni:

UserService service = new UserServiceImpl();

Non raccoglierà il @Autowiredmeno che non lo imposti tu stesso.


2
Allora, qual è l'uso di definire bean idin applicationContext.xml. Dovremo definire la userServicevariabile con il UserServicetipo. Quindi perché effettuare l'iscrizione nel xmlfile.
viper

20

@Autowired è un'annotazione introdotta nella primavera 2.5 ed è utilizzata solo per l'iniezione.

Per esempio:

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
Questo non verrà compilato ed è generalmente errato. @Autowirednon significa che "è possibile utilizzare tutte le funzioni (metodo) e variabili in Bclasse dalla classe A". Ciò che fa è portare un'istanza Ain istanze di B, quindi puoi farlo a.getId()da B.
Dmitry Minkovsky,

@dimadima Quindi, se lo fa System.out.println ("Valore dell'id forma A class" + a.getId ()) ;, e non come ha effettivamente fatto, sarà più corretto. Per favore, rispondi, poiché questo mi è intuitivamente chiaro e secondo il mio attuale livello di comprensione sta spiegando Autowiring.
John Doe,

l'annotazione autowired è stata introdotta nella primavera 2.5 docs.spring.io/spring-framework/docs/2.5.x/api/org/…
SpringLearner

1
Per una migliore sottolineatura, dato che sono nuovo, @autowired crea un'istanza della Classe A usando il costruttore predefinito? In caso contrario, come vengono istanziati i valori in un bean o in un servizio se utilizziamo autowired. Immagino che se chiama il costruttore predefinito, perché usare l'autowiring in primo luogo, basta fare A a = new A (). Si prega di precisare?
Sameer

@Sameer Autowiring le dipendenze è possibile salvare un sacco di codice boilerplate nei test delle unità e anche nelle classi Controller, Service e Dao, poiché l'istanza dei campi viene fornita automaticamente. Non è necessario chiamare il costruttore.
Kiltek,

10

Come @Autowiredfunziona internamente?

Esempio:

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

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

File .xml sarà simile se non si utilizza @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>

Se si utilizza @Autowiredquindi:

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

File .xml sarà simile se non si utilizza @Autowired:

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

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

Se hai ancora qualche dubbio, consulta la demo live di seguito

Come funziona @Autowired internamente?


6

Devi solo annotare la tua classe di servizio UserServiceImplcon l'annotazione:

@Service("userService")

Il contenitore Spring si occuperà del ciclo di vita di questa classe in quanto si registra come servizio.

Quindi nel controller è possibile cablare automaticamente (creare un'istanza) e utilizzare la sua funzionalità:

@Autowired
UserService userService;

3

L'iniezione di dipendenza primaverile ti aiuta a rimuovere l'accoppiamento dalle tue classi. Invece di creare oggetti come questo:

UserService userService = new UserServiceImpl();

Lo userai dopo aver introdotto DI:

@Autowired
private UserService userService;

Per raggiungere questo obiettivo è necessario creare un bean del servizio nel ServiceConfigurationfile. Dopodiché devi importare quella ServiceConfigurationclasse nella tua WebApplicationConfigurationclasse in modo da poter autorizzare quel bean nel tuo Controller in questo modo:

public class AccController {

    @Autowired
    private UserService userService;
} 

È possibile trovare un POC basato sulla configurazione java qui esempio .


1

Modo standard:

@RestController
public class Main {
    UserService userService;

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

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

Interfaccia del servizio utente:

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

Classe UserServiceImpl:

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

Produzione: Example test UserServiceImpl

Questo è un ottimo esempio di classi ad accoppiamento stretto, cattivo esempio di progettazione e ci saranno problemi con i test (anche PowerMockito è male).

Ora diamo un'occhiata all'iniezione di dipendenza SpringBoot, un bell'esempio di accoppiamento lento:

L'interfaccia rimane la stessa,

Classe principale:

@RestController
public class Main {
    UserService userService;

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

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

Classe ServiceUserImpl:

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

Produzione: Example test UserServiceImpl

e ora è facile scrivere test:

@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");
    }
}

Ho mostrato @Autowiredun'annotazione sul costruttore ma può anche essere utilizzata su setter o campo.


0

L'intero concetto di inversione del controllo significa che sei libero da un lavoro di routine per istanziare oggetti manualmente e fornire tutte le dipendenze necessarie. Quando annoti una classe con un'annotazione appropriata (ad es. @Service) Spring istanzia automaticamente l'oggetto per te. Se non si ha familiarità con le annotazioni, è possibile utilizzare anche il file XML. Tuttavia, non è una cattiva idea istanziare manualmente le classi (con la newparola chiave) nei test unitari quando non si desidera caricare l'intero contesto primaverile.


0

Tieni presente che devi abilitare l' @Autowiredannotazione aggiungendo elemento <context:annotation-config/>nel file di configurazione di primavera. Questo registrerà ciò AutowiredAnnotationBeanPostProcessorche si occupa dell'elaborazione delle annotazioni.

E quindi puoi autorizzare il tuo servizio usando il metodo di iniezione sul campo.

public class YourController{

 @Autowired
 private UserService userService; 

}

Ho trovato questo dal post Spring @autowired annotation


0

È possibile creare un'istanza in 3 modi @Autowired.

1. @Autowiredsu Proprietà

L'annotazione può essere utilizzata direttamente sulle proprietà, eliminando quindi la necessità di getter e setter:

    @Component("userService")
    public class UserService {

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

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

Nell'esempio sopra, Spring cerca e inietta userServicequando UserControllerviene creato.

2. @Autowiredsui setter

L' @Autowiredannotazione può essere utilizzata sui metodi setter. Nell'esempio seguente, quando l'annotazione viene utilizzata sul metodo setter, il metodo setter viene chiamato con l'istanza di userServicequando UserControllerviene creato:

public class UserController {

    private UserService userService;

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

3. @Autowiredsui costruttori

L' @Autowiredannotazione può essere utilizzata anche sui costruttori. Nell'esempio seguente, quando l'annotazione viene utilizzata su un costruttore, viene creata un'istanza di userServicecome argomento al costruttore quando UserControllerviene creata:

public class UserController {

    private UserService userService;

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

0

In parole semplici Autowiring, il cablaggio si collega automaticamente, ora arriva la domanda su chi lo fa e su quale tipo di cablaggio. La risposta è: il contenitore fa questo e il tipo di cablaggio secondario è supportato, le primitive devono essere eseguite manualmente.

Domanda: in che modo i container sanno quale tipo di cablaggio?

Risposta: Lo definiamo come byType, byName, costruttore.

Domanda: esiste un modo in cui non definiamo il tipo di autowiring?

Risposta: Sì, è lì facendo una annotazione, @Autowired.

Domanda: Ma come lo sa il sistema, devo scegliere questo tipo di dati secondari?

Risposta: Fornirai quei dati nel tuo file spring.xml o usando le annotazioni sterotype nella tua classe in modo che il contenitore possa creare essi stessi gli oggetti per te.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.