Comprensione della classe Spring @Configuration


108

Seguendo la domanda Understanding Spring @Autowired usage, volevo creare una knowledge base completa per l'altra opzione di cablaggio a molla, la @Configurationclasse.

Supponiamo che io abbia un file XML di primavera simile a questo:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <import resource="another-application-context.xml"/>

  <bean id="someBean" class="stack.overflow.spring.configuration.SomeClassImpl">
    <constructor-arg value="${some.interesting.property}" />
  </bean>

  <bean id="anotherBean" class="stack.overflow.spring.configuration.AnotherClassImpl">
    <constructor-arg ref="someBean"/>
    <constructor-arg ref="beanFromSomewhereElse"/>
  </bean>
</beans>

Come posso usare @Configurationinvece? Ha qualche effetto sul codice stesso?

Risposte:


151

Migrazione di XML a @Configuration

È possibile migrare l'xml in a @Configurationin pochi passaggi:

  1. Crea una @Configurationclasse annotata:

    @Configuration
    public class MyApplicationContext {
    
    }
    
  2. Per ogni <bean>tag creare un metodo annotato con @Bean:

    @Configuration
    public class MyApplicationContext {
    
      @Bean(name = "someBean")
      public SomeClass getSomeClass() {
        return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
      }
    
      @Bean(name = "anotherBean")
      public AnotherClass getAnotherClass() {
        return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
      }
    }
    
  3. Per importare beanFromSomewhereElsedobbiamo importare la sua definizione. Può essere definito in un XML e useremo @ImportResource:

    @ImportResource("another-application-context.xml")
    @Configuration
    public class MyApplicationContext {
      ...  
    }
    

    Se il bean è definito in un'altra @Configurationclasse possiamo usare l' @Importannotazione:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
    
  4. Dopo aver importato altri XML o @Configurationclassi, possiamo usare i bean che dichiarano nel nostro contesto dichiarando un membro privato alla @Configurationclasse come segue:

    @Autowired
    @Qualifier(value = "beanFromSomewhereElse")
    private final StrangeBean beanFromSomewhereElse;
    

    Oppure usalo direttamente come parametro nel metodo che definisce il bean che dipende da questo beanFromSomewhereElseusando @Qualifiercome segue:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
    
  5. L'importazione delle proprietà è molto simile all'importazione del bean da un altro xml o @Configurationclasse. Invece di usare @Qualifieruseremo @Valuecon le proprietà come segue:

    @Autowired
    @Value("${some.interesting.property}")
    private final String someInterestingProperty;
    

    Può essere utilizzato anche con le espressioni SpEL .

  6. Per consentire alla primavera di trattare tali classi come contenitori di fagioli, dobbiamo contrassegnarlo nel nostro XML principale inserendo questo tag nel contesto:

    <context:annotation-config/>

    Ora puoi importare @Configurationclassi esattamente come creeresti un semplice bean:

    <bean class="some.package.MyApplicationContext"/>

    Esistono modi per evitare del tutto gli XML di primavera, ma non rientrano nell'ambito di questa risposta. Puoi scoprire una di queste opzioni nel mio post sul blog su cui sto basando la mia risposta.


I vantaggi e gli svantaggi dell'utilizzo di questo metodo

Fondamentalmente trovo questo metodo per dichiarare i bean molto più comodo rispetto all'utilizzo di XML a causa di alcuni vantaggi che vedo:

  1. Errori di battitura : le @Configurationclassi vengono compilate e gli errori di battitura semplicemente non consentono le compilazioni
  2. Fallire velocemente (tempo di compilazione) - Se dimentichi di iniettare un bean fallirai in fase di compilazione e non in fase di esecuzione come con gli XML
  3. Più facile da navigare nell'IDE : tra i costruttori di bean per comprendere l'albero delle dipendenze.
  4. È possibile eseguire facilmente il debug dell'avvio della configurazione

Gli svantaggi non sono molti come li vedo ma ce ne sono alcuni a cui potrei pensare:

  1. Abuso : è più facile abusare del codice rispetto agli XML
  2. Con gli XML è possibile definire le dipendenze in base alle classi che non sono disponibili durante la compilazione ma vengono fornite durante il runtime. Con le @Configurationclassi devi avere le classi disponibili in fase di compilazione. Di solito non è un problema, ma in alcuni casi potrebbe esserlo.

Conclusione: è perfettamente corretto combinare XML @Configuratione annotazioni nel contesto dell'applicazione. La primavera non si preoccupa del metodo con cui è stato dichiarato un fagiolo.


2
Un possibile svantaggio è la perdita di configurazione. Supponi di avere una classe che prende in giro alcune funzionalità in fase di sviluppo, quindi vuoi sostituirla con un'altra classe nell'ambiente UAT. Utilizzando XML, è solo questione di modificare la configurazione e consentire l'esecuzione / il riavvio dell'applicazione. Con queste nuove configurazioni di classe, le classi dovrebbero essere ricompilate.
Jose

5
@JoseChavez - Questo è un ottimo argomento che ho già sentito un paio di volte. E ho provato a fare alcune ricerche statistiche in cui non sono riuscito a trovare alcuna app o sistema che utilizza XML al di fuori dei suoi barattoli / guerre. Il significato pratico è che devi decomprimere il jar e modificare l'XML (che non sono riuscito a trovare nessuno che lo faccia) o ricostruire i tuoi barattoli (che è quello con cui tutti ho parlato hanno detto di aver fatto finora) . Quindi, in conclusione, poiché può essere un argomento considerevole, di solito non è importante nella vita reale.
Avi

6
Ecco a cosa servono l'annotazione @Profile e la sintassi "$ {env.value}". Con @Profile ("someName") è possibile contrassegnare un'intera configurazione da utilizzare solo quando il profilo è attivo. Nel tuo file application.properties (o .yml), puoi impostare spring.profiles.active = someName, default ... Per impostarlo dinamicamente in base alle variabili d'ambiente, usa la sintassi $ {SOME_ENV_VAR} come valore per spring. active.profiles e imposta la variabile d'ambiente. Spring ora consiglia di utilizzare java config - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Jack Viers

Qual è l'alternativa alla definizione di ogni bean come metodo nel file di configurazione?
Asif Mushtaq

@AsifMushtaq - Puoi usare la funzione di scansione automatica e ogni classe che ha @Component @Serviceo altre annotazioni simili verrebbe automaticamente trasformata in un bean (ma questo non era l'obiettivo di questa domanda)
Avi
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.