[JAVA] Wichtige Änderungen im Zusammenhang mit dem Spring Framework 5.0 DI-Container

Dies ist die dritte Folge der Reihe "Wichtige Änderungen an Spring Framework 5.0" sowie die wichtigsten Änderungen (neue Funktionen und Verbesserungen usw.) in Bezug auf DI-Container. ) Ich möchte vorstellen.

Serie

Version zur Überprüfung des Betriebs

DI-Container-bezogene Änderungen

In Spring Framework 5.0 wurden die folgenden Änderungen am DI-Container vorgenommen.

Artikelnummer Änderungen
1 Möglichkeit, Komponenten aus dem Klassenpfad zu scannen und Beans im DI-Container zu registrieren, wenn die Anwendung ausgeführt wird(@ComponentScan)Als Alternative(Zweck der Verkürzung und Stabilisierung der Startzeit der Anwendung)Infolgedessen wird ein Mechanismus zum Erstellen eines Index von Komponentenkandidaten hinzugefügt, die zur Kompilierungszeit als Bean registriert werden sollen.[Zu Details:arrow_right:]
2 Optionale Einspritzung durch automatische Verkabelung(Möglichkeit)Wird von Ihrer eigenen Bibliothek oder einer Bibliothek eines Drittanbieters bereitgestellt, um dies anzuzeigen@NullableKann angegeben werden.[Zu Details:arrow_right:]

**Note:**Der Anmerkungsname lautet"Nullable"Es wird danach beurteilt, ob es ist oder nicht.
3 GenericApplicationContextWannAnnotationConfigApplicationContextFunktionsschnittstelle(Supplier)Bean Registrierungsmethode mit(registerBean)WannBean定義をカスタマイズするためのインタフェース(BeanDefinitionCustomizer)Wird hinzugefügt werden.[Zu Details:arrow_right:]
4 Wenn Sie AOP auf eine Klasse anwenden, die eine Schnittstelle mithilfe von "CGLIB-Proxy" implementiert(proxyTargetClass=trueWenn angegeben)Die in der Schnittstellenmethode angegebene Anmerkung(@Transactional, @Cacheable, @SyncEine solche)Wird gelesen.[Zu Details:arrow_right:]
5 Generierungsverwaltung der xsd-Datei, die beim Definieren einer Bean in XML angegeben wurde(Bereitstellung von xsd-Dateien für frühere Versionen)Wird abgeschafft und nur xsd-Dateien für die entsprechende Version werden in der JAR-Datei gespeichert.[Zu Details:arrow_right:]

**Note:**Das Angeben einer versionierten xsd-Datei in einer XML-Datei wird weiterhin unterstützt, aber beim Parsen einer XML-Datei wird immer dieselbe xsd-Datei verwendet.

Komponentenindex-Scan unterstützt: thumbsup:

[SPR-11890]: Eine Funktion zum Scannen der Klasse unter dem Paket, das bei der Ausführung der Anwendung angegeben wurde, und zum Registrieren der Bean im DI-Container (@ ComponentScan" ), Standardmäßig wird die Zielklasse zur Laufzeit über den Klassenpfad durchsucht. Bei diesem Mechanismus hängt die zum Scannen einer Klasse erforderliche Zeit von der Paketkonfiguration und der Anzahl der Klassen ab. Ab Spring Framework 5.0 wird ein Mechanismus zum Auflösen von Scan-Kandidatenklassen zur Kompilierungszeit als alternative Methode zum Scannen von Klassenpfaden hinzugefügt (um die Startzeit der Anwendung zu verkürzen oder zu stabilisieren).

Note:

Die Kommentare von JIRA scheinen es nicht dramatisch schneller zu machen, und es scheint es nicht schneller zu machen. Daher ist es besser, basierend auf dem tatsächlichen Effekt zu entscheiden, ob der Index-Scan verwendet werden soll oder nicht. Ich denke. Darüber hinaus war in dem für die Betriebsüberprüfung erstellten Testfall (die Gesamtzahl der Klassen und Klassen von Scan-Kandidaten beträgt etwa 10 Klassen) der Klassenpfad-Scan etwas schneller. (Der Unterschied beträgt ungefähr einige zehn ms: heat_smile :)

Um den Mechanismus kurz zu erklären ... Verwenden der in JDK 1.6, "Indexdatei ( / META-) "hinzugefügten" JSR 269: Pluggable Annotation Processing API "zum Erfassen von Scan-Kandidatenklassen zur Kompilierungszeit INF / spring.components) ”wird erstellt und die Datei zur Laufzeit gelesen. (Wenn Sie versuchen, ein Bild vergeblich zu machen ... sieht es wie folgt aus)

spring50-indexer-overview.png

Die Klassen, die zur Kompilierungszeit aus der Indexdatei ausgegeben werden sollen, sind "zusammengesetzte Annotationen, die" @ Indexed "und" @ Indexed "als Meta-Annotationen (wie" @ Component ") angeben" und Annotationen, die mit "javax." (wie "javax" beginnen). @ Named und @ ManagedBean)" "Paket-Info-Klasse". Zum Zeitpunkt der Ausführung wird die folgende "Karte" (Index) basierend auf der Indexdatei generiert, und die Klassenliste der Scan-Kandidaten wird erfasst, ohne das zu scannende Paket tatsächlich nach Komponenten zu scannen.

spring50-indexer-indexmap.png

Wie beim Klassenpfadscan werden "Klassen außerhalb des zu scannenden Pakets", "Klassen, die mit dem Ausschlussfilter übereinstimmen" und "Klassen, die nicht mit dem Einschlussfilter übereinstimmen" nicht im DI-Container registriert.

Das Aktivieren des Index-Scannens ist einfach. Fügen Sie einfach das Modul "Spring-Context-Indexer" zu den abhängigen Artefakten wie folgt hinzu:

pom.xml


<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-indexer</artifactId>
  <version>5.0.0.RC1</version>
  <optional>true</optional> <!--Es ist nur beim Kompilieren notwendig, also nicht im Krieg verpacken usw.-->
</dependency>

Note:

Wenn sich mindestens eine gültige Indexdatei (/ META-INF / spring.components) im Klassenpfad befindet, wird standardmäßig der Index-Scan verwendet. Wenn Ihr Projekt beispielsweise keinen "Spring-Context-Indexer" verwendet, die abhängigen Bibliotheken (z. B. die allgemeine Bibliothek Ihres Unternehmens) Indexdateien enthalten, werden die Komponenten Ihres Projekts nicht gescannt. Um dieses Phänomen zu vermeiden, haben Sie zwei Möglichkeiten: "Verwenden Sie" Spring-Context-Indexer "in Ihrem eigenen Projekt" oder "Scannen Sie den Index nicht zur Laufzeit". Um "das Scannen von Indizes zur Laufzeit zu verhindern", gehen Sie zu "Spring Properties File ( spring.properties direkt unter dem Klassenpfad) "oder" Java System Properties (-D Option)" zu " spring Bitte geben Sie .index.ignore = true "an.

@ Nullable kann für jeden Injektionspunkt angegeben werden: thumbsup:

[SPR-15028]: Eine selbst erstellte Bibliothek oder eine Bibliothek eines Drittanbieters ([SPR-15028]): Wenn angegeben wird, dass die Injektion durch automatische Verkabelung optional ist (optional) Sie können das von JSR-305 bereitgestellte "@ Nullable" angeben.

Note:

Intern wird beurteilt, ob der Anmerkungsname "Nullable" ist oder nicht, sodass auch Ihr eigenes "@ Nullable" erkannt wird.

Zum Beispiel ...

〜4.3


@Component
public class Foo {

	private final Bar bar;
	private final Baz baz;

	public Foo(Bar bar, @Autowired(required = false) Baz baz) {
		this.bar = bar;
		this.baz = baz;
	}

}

Kann auch in einem Stil umgeschrieben werden, der keine Spring Framework-Annotationen verwendet (Beispiel: JSR-330-Annotation + JSR-305 @ Nullable), wie unten gezeigt.

pom.xml


<dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
</dependency>
<dependency>
  <groupId>com.google.code.findbugs</groupId>
  <artifactId>jsr305</artifactId>
  <version>3.0.2</version>
</dependency>

@Verwendung von Nullable(5.0〜)


import javax.annotation.Nullable;
import javax.inject.Named;
//...
@Named
public class Foo {

	private final Bar bar;
	private final Baz baz;

	public Foo(Bar bar, @Nullable Baz baz) {
		this.bar = bar;
		this.baz = baz;
	}

}

Übrigens ... JSR-330-Annotationen (@ Named und @ Inject) können auch in Spring Framework 4.3 verwendet werden. Sie können auch das in JDK 8 hinzugefügte java.util.Optional verwenden, um anzuzeigen, dass es sich um einen beliebigen Injektionspunkt handelt.

Verwendung von Optional


import java.util.Optional;
// ...
@Named
public class Foo {

	private final Bar bar;
	private final Optional<Baz> baz;

	public Foo(Bar bar, Optional<Baz> baz) {
		this.bar = bar;
		this.baz = baz;
	}

}

Bohnen können über die Funktionsschnittstelle (Lieferant) registriert werden: thumbsup:

[SPR-14832]: Bean-Registrierungsmethode (Supplier) unter Verwendung der Funktionsschnittstelle ( Supplier) für GenericApplicationContext und AnnotationConfigApplicationContext Eine registerBean) und eine Schnittstelle zum Anpassen von Bean-Definitionen (BeanDefinitionCustomizer`) werden hinzugefügt.

Wenn Sie beispielsweise Folgendes tun, wird das von dem im Lambda-Ausdruck angegebenen "Lieferanten" zurückgegebene Objekt im DI-Container als Singleton-Bean verwaltet.

Bohnengenerierung und Registrierung mit dem Lieferanten


try (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {
	applicationContext.registerBean(Bar.class);
	applicationContext.registerBean(Foo.class, () -> new Foo(applicationContext.getBean(Bar.class))); //★★★ Bean Registrierung mit dem Lieferanten
	applicationContext.refresh();

	Foo foo = applicationContext.getBean(Foo.class);

	// ...
}

Darüber hinaus ... Mithilfe der BeanDefinitionCustomizer-Schnittstelle können Sie die Metainformationen (Bereich usw.) der vom DI-Container verwalteten Bean angeben. Im folgenden Beispiel wird der Umfang der Bean in einen Prototyp geändert.

java:org.springframework.beans.factory.config.BeanDefinitionCustomizer


@FunctionalInterface
public interface BeanDefinitionCustomizer {
	void customize(BeanDefinition bd);
}

Beispiel für die Anpassung der Bean-Definition mit BeanDefinitionCustomizer


try (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {
	applicationContext.registerBean(Bar.class);
	applicationContext.registerBean(Foo.class, () -> new Foo(applicationContext.getBean(Bar.class)),
			bd -> bd.setScope(BeanDefinition.SCOPE_PROTOTYPE)); //★★★ Passen Sie Bean-Definitionen mit BeanDefinitionCustomizer an
	applicationContext.refresh();

	Foo foo = applicationContext.getBean(Foo.class);

	Assertions.assertFalse(foo == applicationContext.getBean(Foo.class)); //Da es sich bei dem Bereich um einen Prototyp handelt, werden beim ersten und beim zweiten Mal unterschiedliche Instanzen zurückgegeben
}

Note:

Übrigens ... Wenn Sie die von Spring bereitgestellten Anmerkungen nicht verwenden möchten (möchten Sie annotationsgesteuert entwickeln?), Können Sie auch "GenericApplicationContext" verwenden.

Die für die Schnittstelle angegebene Anmerkung wird bei Verwendung von "CGLIB-Proxy" gelesen: thumbsup:

[SPR-14322 usw.]: Beim Anwenden von AOP auf eine Klasse, die eine Schnittstelle mit "Proxy of CGLIB" (`) implementiert Wenn proxyTargetClass = true angegeben ist, werden die in der Schnittstellenmethode angegebenen Anmerkungen ("@ Transactional", "@ Cacheable", "@ Sync" usw.) gelesen.

Wenn Sie beispielsweise die Cache-Funktion von Spring wie unten gezeigt verwenden, kommentieren Sie die Schnittstelle mit der Cache-Steuerung.

Schnittstelle


@CacheConfig(cacheNames = "accounts")
public interface AccountService {
	@Cacheable
	Account getAccount(int id);
}

Implementierungsklasse


public class AccountServiceImpl implements AccountService {
	@Override
	public Account getAccount(int id) {
		return new Account(id);
	}
}

Die Konfigurationsklasse verwendet beim Anwenden der Spring-Caching-Funktion (beim Erstellen eines Proxy-Objekts) den CGLIB-Proxy anstelle des JDK-Proxys.

Aufbau


@EnableCaching(proxyTargetClass = true) //★★★ Stellen Sie CGLIB Proxy ein
@Configuration
public static class CacheConfiguration {
	@Bean
	CacheManager cacheManager() {
		return new ConcurrentMapCacheManager("accounts");
	}
	@Bean
	AccountService accountService() {
		return new AccountServiceImpl();
	}
}

Wenn Sie in diesem Status die aus dem Anwendungskontext erhaltene AccountService-Methode zweimal mit demselben Argument aufrufen, wird das zwischengespeicherte Objekt das zweite Mal zurückgegeben.

python


try (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
		CacheConfiguration.class)) {

	AccountService service = applicationContext.getBean(AccountService.class);

	Account account = service.getAccount(1);

	Assertions.assertTrue(account == service.getAccount(1)); //Die Cache-Funktion von Spring wird angewendet und das zwischengespeicherte Objekt wird das zweite Mal zurückgegeben.
}

Abschaffung der Generierungsverwaltung von xsd-Dateien

[SPR-13499]: Generierungsverwaltung von xsd-Dateien, die beim Definieren von Beans in XML angegeben wurden (Bereitstellung von xsd-Dateien für frühere Versionen) Es ist veraltet und nur xsd-Dateien für diese Version werden in der JAR-Datei gespeichert. Das Angeben einer versionierten xsd-Datei in einer XML-Datei wird weiterhin unterstützt, aber beim Parsen einer XML-Datei wird immer dieselbe xsd-Datei verwendet.

In Spring Framework 4.3 konnten Attribute, die in früheren Versionen unterstützt wurden, wie folgt verwendet werden.

Bean-Definitions-XML-Datei


<?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.2.xsd"> <!-- ★★★ 3.Geben Sie die XSD-Datei für 2 an-->

  <bean class="com.example.di.Foo">
    <property name="bar">
      <ref local="bar"/> <!-- ★★★ 3.x hat ein lokales Attribut-->
    </property>
  </bean>

  <bean id="bar" class="com.example.di.Bar"/>

</beans>

Wenn Sie diese Datei mit Spring Framework 5.0 verwenden ... Beim Parsen einer XML-Datei tritt eine Schemaverletzung auf und der folgende Fehler tritt auf.

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 9 in XML document from class path resource [com/example/di/applicationContext.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 25; cvc-complex-type.3.2.2:Element'ref'Zuschreiben'local'Kann nicht enthalten sein.

	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:399)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)

Um diese Datei in Spring Framework 5.0 verwenden zu können, müssen Maßnahmen wie "Änderung in" Bean "-Attribut anstelle von" Local "-Attribut" oder "Use Ref" -Attribut von "<Eigenschaft>" -Element "ergriffen werden. Werden. Das " local-Attribut des ` -Elements "ist ein Beispiel für ein Attribut, das nicht verwendet werden kann, und mehrere andere können nicht verwendet werden.

Beispiel für die Änderung des Bean-Attributs


<bean class="com.example.di.Foo">
  <property name="bar">
    <ref bean="bar"/>
  </property>
</bean>

<property>Beispiel für die Verwendung des ref-Attributs des Elements


<bean class="com.example.di.Foo">
  <property name="bar" ref="bar"/>
</bean>

Es macht auch keinen Sinn, die Version anzugeben, wenn die XSD-Datei angegeben wird (ziemlich verwirrend). Daher wird empfohlen, die XSD-Datei zu ändern, die die Version bei dieser Gelegenheit nicht enthält.

Beispiel für die Angabe einer nicht versionierten XSD-Datei


<?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.xsd"> <!--★★★ Wechseln Sie in eine nicht versionierte Datei-->

  <!-- ... -->

</beans>

Zusammenfassung

Dieses Mal haben wir die wichtigsten Änderungen in Bezug auf DI-Container vorgestellt. Vielleicht ist "Index-Scan-Unterstützung" die wichtigste Änderung, aber sie scheint nicht dramatisch schneller zu starten. Freuen Sie sich also auf zukünftige Verbesserungen! !! Ist es so etwas wie: zwinker: Nächstes Mal werde ich "Wichtige Änderungen in Bezug auf WebMVC" vorstellen.

Recommended Posts

Wichtige Änderungen im Zusammenhang mit dem Spring Framework 5.0 DI-Container
Wichtige Änderungen im Zusammenhang mit Spring Framework 5.0 Test
Wichtige Änderungen in Bezug auf Spring Framework 5.0 Web MVC
Anmerkungen zur Spring Framework-Studie [Teil 1] DI-Container
Wichtige Änderungen in der Kernfunktionalität von Spring Framework 5.0
Spring Framework Zusammenfassung - Über DI
Einführung in Spring Boot ~ ~ DI ~
Wichtige Änderungen in Spring Boot 1.5
Informationen zu Anmerkungen zu Spring DI
Änderungen bei der Migration von Spring Boot 1.5 auf Spring Boot 2.0
Änderungen bei der Migration von Spring Boot 2.0 zu Spring Boot 2.2
Ich habe versucht, JavaFX und Spring Framework zu verknüpfen.
[Java] Spring DI ③
Versuchen Sie es mit einem DI-Container mit Laravel und Spring Boot
So stellen Sie Spring Boot Dependency Injection (DI) ein
Verwendung von Struts2 * Spring Framework (Spring Plugin) Version Juni 2017