[JAVA] Modifications majeures liées au conteneur Spring Framework 5.0 DI

Ceci est le troisième volet de la série «Spring Framework 5.0 Major Changes» et les principaux changements (nouvelles fonctions et améliorations, etc.) liés aux conteneurs DI. ) Je voudrais présenter.

séries

Version de vérification de fonctionnement

Modifications liées au conteneur DI

Dans Spring Framework 5.0, les modifications suivantes ont été apportées au conteneur DI.

Numéro d'article Changements
1 Possibilité de scanner les composants à partir du chemin de classe et d'enregistrer les beans dans le conteneur DI lorsque l'application est exécutée(@ComponentScan)Alternative à(Objectif de raccourcir et de stabiliser le temps de démarrage de l'application)En conséquence, un mécanisme pour créer un index des composants candidats à enregistrer en tant que beans lors de la compilation sera ajouté.[Vers les détails:arrow_right:]
2 Injection optionnelle par câblage automatique(option)Fourni à partir de votre propre bibliothèque ou d'une bibliothèque tierce pour indiquer que@NullableSera en mesure d'être spécifié.[Vers les détails:arrow_right:]

**Note:**Le nom de l'annotation est"Nullable"Elle est jugée par si oui ou non.
3 GenericApplicationContextQuandAnnotationConfigApplicationContextInterface fonctionnelle(Supplier)Méthode d'enregistrement Bean utilisant(registerBean)QuandBean定義をカスタマイズするためのインタフェース(BeanDefinitionCustomizer)Sera ajouté.[Vers les détails:arrow_right:]
4 Lors de l'application d'AOP à une classe qui implémente une interface à l'aide de "CGLIB Proxy"(proxyTargetClass=trueLorsque spécifié)L'annotation spécifiée dans la méthode d'interface(@Transactional, @Cacheable, @SyncTel)Sera lu.[Vers les détails:arrow_right:]
5 Gestion de la génération du fichier xsd spécifié lors de la définition d'un bean en XML(Fournir des fichiers xsd pour les versions antérieures)Sera aboli et seuls les fichiers xsd de cette version seront stockés dans le fichier JAR.[Vers les détails:arrow_right:]

**Note:**La spécification d'un fichier xsd versionné dans un fichier XML est toujours prise en charge, mais le même fichier xsd est toujours utilisé lors de l'analyse d'un fichier XML.

Analyse de l'index des composants prise en charge: pouce levé:

[SPR-11890]: Une fonction pour scanner la classe sous le package spécifié lorsque l'application est exécutée et enregistrer le bean dans le conteneur DI (@ ComponentScan" ), Mais par défaut, la classe cible est recherchée à partir du chemin de classe lors de l'exécution. Avec ce mécanisme, le temps nécessaire pour analyser une classe dépend de la configuration du package et du nombre de classes. À partir de Spring Framework 5.0, un mécanisme pour résoudre les classes candidates à l'analyse au moment de la compilation sera ajouté comme méthode alternative d'analyse du chemin de classe (dans le but de raccourcir ou de stabiliser le temps de démarrage de l'application).

Note:

Les commentaires de JIRA ne semblent pas le rendre considérablement plus rapide, et cela ne semble pas le rendre plus rapide, il est donc préférable de voir l'effet et de décider d'utiliser ou non l'analyse d'index. Je pense. En outre, dans le cas de test créé pour la vérification des opérations (le nombre total de classes et de classes candidates à l'analyse est d'environ 10 classes), l'analyse du chemin de classe a été légèrement plus rapide. (La différence est d'environ plusieurs dizaines de msec: sweat_smile :)

Pour expliquer brièvement le mécanisme ... En utilisant le "JSR 269: API de traitement d'annotations enfichables" ajouté dans JDK 1.6, "Fichier d'index ( / META-) pour l'acquisition de classes candidates au scan au moment de la compilation INF / spring.components) »est créé et le fichier est lu lors de l'exécution. (Si vous essayez de faire une image en vain ... cela ressemble à ce qui suit)

spring50-indexer-overview.png

Les classes à sortir du fichier d'index au moment de la compilation sont des "annotations composites qui spécifient @ Indexed et" @ Indexed comme des méta-annotations (telles que @ Component) "et des annotations qui commencent par javax. (comme" javax. ". @ Named et @ ManagedBean)" "classe d'info-package". Au moment de l'exécution, la «carte» (index) suivante est générée sur la base du fichier d'index, et la liste de classe des candidats à l'analyse est acquise sans analyser réellement le paquet à analyser pour les composants.

spring50-indexer-indexmap.png

Comme pour l'analyse de chemin de classe, les «classes en dehors du package à analyser», «les classes qui correspondent au filtre d'exclusion» et «les classes qui ne correspondent pas au filtre d'inclusion» ne sont pas enregistrées dans le conteneur DI.

L'activation de l'analyse d'index est facile, ajoutez simplement le module spring-context-indexer aux artefacts dépendants comme suit:

pom.xml


<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-indexer</artifactId>
  <version>5.0.0.RC1</version>
  <optional>true</optional> <!--Il n'est nécessaire que lors de la compilation, donc ne le conditionnez pas dans war, etc.-->
</dependency>

Note:

S'il y a au moins un fichier d'index valide (/ META-INF / spring.components) sur le chemin de classe, l'analyse d'index est utilisée par défaut. Par exemple, si votre projet n'utilise pas spring-context-indexer, mais que ses bibliothèques dépendantes (telles que la bibliothèque commune de votre entreprise) contiennent des fichiers d'index, les composants de votre projet ne seront pas analysés. Pour éviter ce phénomène, vous avez deux choix: "Utiliser spring-context-indexer dans votre propre projet" ou "Ne pas scanner l'index lors de l'exécution". Pour "empêcher l'analyse d'index lors de l'exécution", allez dans "Spring Properties File ( spring.properties directement sous le chemin de la classe) "ou" Java System Properties (option -D)" à " spring Veuillez spécifier .index.ignore = true ".

@ Nullable peut être spécifié pour n'importe quel point d'injection: thumbsup:

[SPR-15028]: une librairie indépendante ou tierce ([SPR-15028]): lorsque l'injection par câblage automatique est facultative (facultative) Vous pourrez spécifier le @ Nullable fourni par JSR-305.

Note:

En interne, il juge si le nom de l'annotation est «" Nullable "» ou non, donc il reconnaît également votre propre «@ Nullable».

Par exemple ...

〜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;
	}

}

Peut également être réécrit dans un style qui n'utilise pas les annotations Spring Framework (exemple: annotation JSR-330 + JSR-305 @ Nullable) comme indiqué ci-dessous.

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>

@Utilisation de 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;
	}

}

Au fait ... Les annotations JSR-330 (@ Named et @ Inject) peuvent également être utilisées dans Spring Framework 4.3. Vous pouvez également utiliser le java.util.Optional ajouté dans JDK 8 pour indiquer qu'il s'agit d'un point d'injection arbitraire.

Utilisation facultative


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;
	}

}

Les beans peuvent être enregistrés à l'aide de l'interface fonctionnelle (Supplier): thumbsup:

[SPR-14832]: Méthode d'enregistrement du bean (Supplier) utilisant l'interface fonctionnelle ( Supplier) pour GenericApplicationContext et ʻAnnotationConfigApplicationContext Un registerBean) et une interface pour personnaliser les définitions de bean (BeanDefinitionCustomizer) sont ajoutés.

Par exemple, si vous procédez comme suit, l'objet renvoyé par le Supplier spécifié dans l'expression lambda sera géré dans le conteneur DI en tant que bean singleton.

Génération et enregistrement de haricots à l'aide du fournisseur


try (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {
	applicationContext.registerBean(Bar.class);
	applicationContext.registerBean(Foo.class, () -> new Foo(applicationContext.getBean(Bar.class))); //★★★ Enregistrement des haricots à l'aide du fournisseur
	applicationContext.refresh();

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

	// ...
}

De plus ... En utilisant l'interface BeanDefinitionCustomizer, vous pouvez spécifier les méta-informations (portée, etc.) du bean géré par le conteneur DI. Dans l'exemple ci-dessous, la portée du bean est modifiée en prototype.

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


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

Exemple de personnalisation de la définition de bean à l'aide de 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)); //★★★ Personnalisez les définitions de bean avec BeanDefinitionCustomizer
	applicationContext.refresh();

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

	Assertions.assertFalse(foo == applicationContext.getBean(Foo.class)); //Étant donné que la portée est un prototype, différentes instances sont renvoyées la première et la deuxième fois
}

Note:

Au fait ... Si vous ne voulez pas utiliser les annotations fournies par Spring (voulez-vous faire du développement basé sur les annotations?), Vous pouvez également utiliser GenericApplicationContext.

L'annotation spécifiée pour l'interface est lue lors de l'utilisation de "CGLIB Proxy": thumbsup:

[SPR-14322 etc.]: Lors de l'application d'AOP à une classe qui implémente une interface en utilisant "Proxy of CGLIB" ( Lorsque proxyTargetClass = true est spécifié), les annotations spécifiées dans la méthode d'interface (@ Transactional, @ Cacheable, @ Sync, etc.) seront lues.

Par exemple, lorsque vous utilisez la fonction de cache de Spring comme indiqué ci-dessous, annotez l'interface avec le contrôle de cache.

interface


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

Classe d'implémentation


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

La classe de configuration est définie pour utiliser le proxy CGLIB au lieu du proxy JDK lors de l'application de la fonction de mise en cache Spring (lors de la création d'un objet Proxy).

configuration


@EnableCaching(proxyTargetClass = true) //★★★ Configuré pour utiliser le proxy CGLIB
@Configuration
public static class CacheConfiguration {
	@Bean
	CacheManager cacheManager() {
		return new ConcurrentMapCacheManager("accounts");
	}
	@Bean
	AccountService accountService() {
		return new AccountServiceImpl();
	}
}

Dans cet état, si vous appelez la méthode AccountService obtenue à partir du contexte d'application deux fois avec le même argument, l'objet mis en cache sera renvoyé la deuxième fois.

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)); //La fonction de cache de Spring est appliquée et l'objet mis en cache est renvoyé la deuxième fois.
}

Suppression de la gestion de la génération des fichiers xsd

[SPR-13499]: Gestion de la génération des fichiers xsd spécifiés lors de la définition des beans en XML (fournissant des fichiers xsd pour les versions antérieures) Il sera obsolète et seuls les fichiers xsd de cette version seront stockés dans le fichier JAR. La spécification d'un fichier xsd versionné dans un fichier XML est toujours prise en charge, mais le même fichier xsd est toujours utilisé lors de l'analyse d'un fichier XML.

Sur Spring Framework 4.3, il était possible d'utiliser les attributs pris en charge dans les versions précédentes comme suit.

Fichier XML de définition de bean


<?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.Spécifiez le fichier XSD pour 2-->

  <bean class="com.example.di.Foo">
    <property name="bar">
      <ref local="bar"/> <!-- ★★★ 3.x a un attribut local-->
    </property>
  </bean>

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

</beans>

Si vous utilisez ce fichier avec Spring Framework 5.0 ... Lors de l'analyse d'un fichier XML, une violation de schéma se produit et l'erreur suivante se produit.

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:élément'ref'Attribuer à'local'Ne peut pas être inclus.

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

Pour utiliser ce fichier sur Spring Framework 5.0, il est nécessaire de prendre des mesures telles que "modifier l'attribut" bean "au lieu de l'attribut" local "ou" utiliser "l'attribut ref de l'élément" ". Devenir. L'attribut " local de l'élément <ref> "est un exemple d'attribut qui ne peut pas être utilisé, et plusieurs autres ne peuvent pas être utilisés.

Exemple de changement d'attribut bean


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

<property>Exemple d'utilisation de l'attribut ref de l'élément


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

De plus, il est inutile de spécifier la version lors de la spécification du fichier XSD (assez déroutant), il est donc recommandé de changer pour spécifier le fichier XSD qui n'inclut pas la version à cette occasion.

Exemple de spécification d'un fichier XSD non versionné


<?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"> <!--★★★ Passer au fichier non versionné-->

  <!-- ... -->

</beans>

Résumé

Cette fois, nous avons présenté les principaux changements liés aux conteneurs DI. Peut-être que "la prise en charge de l'analyse d'index" est le principal changement, mais il ne semble pas démarrer beaucoup plus rapidement, alors attendez-vous à de futures améliorations! !! Est-ce quelque chose comme: wink: La prochaine fois, je présenterai "Changements majeurs liés à WebMVC".

Recommended Posts

Modifications majeures liées au conteneur Spring Framework 5.0 DI
Modifications majeures liées au test Spring Framework 5.0
Modifications majeures liées à Spring Framework 5.0 Web MVC
Notes de l'étude Spring Framework [Partie 1] Conteneur DI
Changements majeurs dans la fonctionnalité de base de Spring Framework 5.0
Résumé de Spring Framework - À propos de DI
Introduction à Spring Boot ① ~ DI ~
Changements majeurs dans Spring Boot 1.5
À propos des annotations liées à Spring DI
Modifications lors de la migration de Spring Boot 1.5 vers Spring Boot 2.0
Modifications lors de la migration de Spring Boot 2.0 vers Spring Boot 2.2
J'ai essayé de lier JavaFX et Spring Framework.
[Java] Spring DI ③
Essayez d'utiliser un conteneur DI avec Laravel et Spring Boot
Comment définir l'injection de dépendance Spring Boot (DI)
Comment utiliser Struts2 * Spring Framework (plugin Spring) Version de juin 2017