Grundlegendes zur spring @ Configuration-Klasse

108

Nach der Frage zur Verwendung von Spring @Autowired wollte ich eine vollständige Wissensbasis für die andere Option der Federverdrahtung, die @ConfigurationKlasse , erstellen .

Nehmen wir an, ich habe eine Spring-XML-Datei, die so aussieht:

<?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>

Wie kann ich @Configurationstattdessen verwenden? Hat es Auswirkungen auf den Code selbst?

Avi
quelle

Antworten:

151

XML migrieren nach @Configuration

Es ist möglich, die XML-Datei @Configurationin wenigen Schritten auf a zu migrieren :

  1. Erstellen Sie eine mit @ConfigurationAnmerkungen versehene Klasse:

    @Configuration
    public class MyApplicationContext {
    
    }
  2. <bean>Erstellen Sie für jedes Tag eine Methode mit @Beanfolgenden Anmerkungen :

    @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. Um zu importieren beanFromSomewhereElse, müssen wir seine Definition importieren. Es kann in einem XML definiert werden und das werden wir verwenden @ImportResource:

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

    Wenn die Bean in einer anderen @ConfigurationKlasse definiert ist, können wir die @ImportAnnotation verwenden:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
  4. Nachdem wir andere XMLs oder @ConfigurationKlassen importiert haben , können wir die Beans verwenden, die sie in unserem Kontext deklarieren, indem wir ein privates Mitglied für die @ConfigurationKlasse wie folgt deklarieren :

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

    Oder es direkt als Parameter in dem Verfahren verwendet werden, die in den Bohnen definiert , die davon abhängt beanFromSomewhereElseVerwendung @Qualifierwie folgt:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
  5. Das Importieren von Eigenschaften ist dem Importieren von Bean aus einer anderen XML-Datei oder @ConfigurationKlasse sehr ähnlich . Anstatt zu verwenden, verwenden @Qualifierwir @Valuefolgende Eigenschaften:

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

    Dies kann auch mit SpEL- Ausdrücken verwendet werden.

  6. Damit spring solche Klassen als Bohnenbehälter behandeln kann, müssen wir dies in unserer Haupt-XML markieren, indem wir dieses Tag in den Kontext einfügen:

    <context:annotation-config/>

    Sie können jetzt @ConfigurationKlassen genauso importieren , wie Sie eine einfache Bean erstellen würden:

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

    Es gibt Möglichkeiten, Spring-XMLs insgesamt zu vermeiden, sie fallen jedoch nicht in den Geltungsbereich dieser Antwort. Eine dieser Optionen finden Sie in meinem Blog-Beitrag, auf den ich meine Antwort stütze.


Die Vor- und Nachteile dieser Methode

Grundsätzlich finde ich diese Methode zum Deklarieren von Beans aufgrund einiger Vorteile, die ich sehe, viel komfortabler als die Verwendung von XMLs:

  1. Typos - @ConfigurationKlassen werden zusammengestellt und Tippfehler werden nur nicht zulassen , dass Compilations
  2. Schnell fehlschlagen (Kompilierungszeit) - Wenn Sie vergessen, eine Bean einzufügen, schlagen Sie zur Kompilierungszeit und nicht zur Laufzeit wie bei XMLs fehl
  3. Einfachere Navigation in der IDE - zwischen Konstruktoren von Beans, um den Abhängigkeitsbaum zu verstehen.
  4. Mögliches einfaches Debuggen des Konfigurationsstarts

Die Nachteile sind nicht viele, wie ich sie sehe, aber es gibt einige, an die ich denken könnte:

  1. Missbrauch - Code ist leichter zu missbrauchen als XMLs
  2. Mit XMLs können Sie Abhängigkeiten basierend auf Klassen definieren, die während der Kompilierungszeit nicht verfügbar sind, aber zur Laufzeit bereitgestellt werden. Bei @ConfigurationKlassen müssen die Klassen zur Kompilierungszeit verfügbar sein. Normalerweise ist das kein Problem, aber es kann Fälle geben.

Fazit: Es ist vollkommen in Ordnung, XMLs @Configurationund Anmerkungen in Ihrem Anwendungskontext zu kombinieren . Spring kümmert sich nicht um die Methode, mit der eine Bohne deklariert wurde.

Avi
quelle
2
Ein möglicher Nachteil ist der Konfigurationsverlust. Angenommen, Sie haben eine Klasse, die einige Funktionen in der Entwicklung verspottet, und möchten sie dann gegen eine andere Klasse in der UAT-Umgebung austauschen. Wenn Sie XML verwenden, müssen Sie nur die Konfiguration ändern und die Anwendung ausführen / neu starten. Mit diesen neuen Klassenkonfigurationen müssten die Klassen neu kompiliert werden.
Jose
5
@JoseChavez - Das ist ein großartiges Argument, das ich schon ein paar Mal gehört habe. Und ich habe versucht, statistische Recherchen durchzuführen, bei denen ich keine App oder kein System finden konnte, das XMLs außerhalb seiner Jars / Wars verwendet. Die praktische Bedeutung davon ist, dass Sie entweder das Glas entpacken und das XML ändern müssen (was ich niemanden finden konnte, der das tut) oder Ihre Gläser neu erstellen müssen (was alle, mit denen ich gesprochen habe, gesagt haben, dass sie es bisher getan haben). . Fazit: Da dies ein beträchtliches Argument sein kann, ist es im wirklichen Leben normalerweise nicht wichtig.
Avi
6
Dafür sind die Annotation @Profile und die Syntax "$ {env.value}" gedacht. Mit @Profile ("someName") können Sie eine gesamte Konfiguration nur zur Verwendung markieren, wenn das Profil aktiv ist. In Ihrer Datei application.properties (oder .yml) können Sie spring.profiles.active = someName als Standard festlegen. Um sie dynamisch basierend auf Umgebungsvariablen festzulegen, verwenden Sie die Syntax $ {SOME_ENV_VAR} als Wert für spring. active.profiles und legen Sie die Umgebungsvariable fest. Spring empfiehlt jetzt die Verwendung von Java Config - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Jack Viers
Was ist eine Alternative, als jede Bean als Methode in der Konfigurationsdatei zu definieren?
Asif Mushtaq
@AsifMushtaq - Sie können die Autoscan-Funktion verwenden und jede Klasse, die @Component @Serviceoder andere solche Anmerkungen hat, würde automatisch in eine Bean umgewandelt (aber das war nicht der Fokus dieser Frage)
Avi