Fermer

janvier 20, 2022

Introduction à Spring Framework pour Java


Cet article présente les bases de l'utilisation de Spring Framework pour Java.

D'un point de vue très, très élevé, Spring Framework déduit le comportement d'exécution d'un programme à partir d'étiquettes que le programmeur attache à des morceaux de code. Il existe de nombreux groupements d'étiquettes différents, et chaque groupement d'étiquettes fournit une interface pour la configuration d'un processus en arrière-plan.

Étant donné qu'un programme Spring Framework d'apparence simple avec seulement quelques étiquettes peut avoir beaucoup de choses à faire dans les coulisses, l'apprentissage de Spring Framework peut sembler un peu écrasant pour le débutant. L'apprentissage est rendu encore plus difficile par le fait que la plupart des ressources en ligne documentant Spring Framework parcourent au hasard différents types d'étiquettes au lieu de construire une compréhension fondamentale.

Cet article vise à combler cette lacune et à fournir une compréhension de base. Nous commencerons par Java vanille, puis, un modèle de conception de programmation à la fois, nous augmenterons notre compréhension de la façon dont ce modèle de conception est configuré dans Spring Framework avec des étiquettes.

Avant de commencer à lire sérieusement cet article…[19659006]Vous devez connaître les bases des annotations Java. Les "étiquettes" dont il a été question ci-dessus sont en réalité des annotations. J'ai mentionné que la plupart des ressources en ligne sur Spring Framework sont désorganisées et décevantes; son article est l'une des rares exceptions. Il est toujours bon d'avoir plusieurs lectures à partir desquelles apprendre un sujet, et je vous encourage donc à lire cet article en complément de celui-ci. déduit le comportement d'exécution d'un programme à partir d'annotations Java. Il s'agit d'une description précise au niveau de la surface de Spring Framework, mais ce n'est pas une bonne caractérisation à partir de laquelle développer une compréhension fondamentale.

Nous commencerons notre compréhension de Spring Framework avec une caractérisation différente. À la base, Spring Framework est un outil pour implémenter le modèle de conception appelé injection de dépendances.

Dans injection de dépendancesles instances d'objet sur class Cls depends sont "injectés" dans une instance obj de Cls par un conteneur qui fait référence à obj. Étant donné que le conteneur, plutôt que objcontrôle le moment où les dépendances de obj sont injectées, il est souvent appelé une inversion du conteneur de contrôle. L'injection de dépendance est aussi parfois appelée "inversion de contrôle" pour cette raison.

Quel est l'intérêt de l'injection de dépendance ? Cela nous permet d'éviter d'instancier des copies inutiles d'une dépendance.

Supposons que plusieurs classes nécessitent une référence à un objet qui représente une connexion à une base de données particulière. Étant donné que cette référence est une dépendance, nous pouvons facilement partager une seule connexion de base de données entre toutes les instances de classe en utilisant la technique d'injection de dépendance décrite ci-dessus. C'est bien mieux que de donner inutilement à chaque instance de classe sa propre connexion à la base de données.

Lorsque vous utilisez Spring Framework, nous passerons la plupart de notre temps à traiter et à penser aux « haricots Spring », qui sont les dépendances gérées par le Spring Framework. Conteneur IoC.

Pour être plus précis, un bean Spring est un objet non-nécessairement-sérialisable qui…

  • est créé au moment de l'exécution par le conteneur Spring IoC (IoC signifie inversion de contrôle)

  • a des références à d'autres objets ou beans ("dépendances") qui lui sont injectés au moment de l'exécution par le conteneur Spring IoC

  • est autrement contrôlé au moment de l'exécution par le conteneur Spring IoC.

Les beans Spring peuvent être configurés via des fichiers XML ou en utilisant des annotations Java dans les classes Java. L'utilisation d'annotations est l'approche moderne. Cet article n'utilisera que des annotations – pas de code XML.

Notez qu'un bean Spring est différent d'un JavaBean. Les JavaBeans font partie du noyau du langage Java, contrairement aux Spring beans. (Plus précisément, un JavaBean est une classe Serializable avec un constructeur public sans argument qui a tous les champs private).

Dans ce qui précède, nous avons dit que les beans Spring sont créés au moment de l'exécution par le conteneur Spring IoC. Mais comment le conteneur Spring IoC sait-il quel type de beans créer ? Eh bien, vous, le programmeur, devez écrire un « code de configuration » qui spécifie quelles classes Java doivent être instanciées en tant que beans Spring lors de l'exécution. l'annotation ou l'annotation @Component . (Vous pouvez également utiliser une annotation dérivée de @Component).

Première méthode de configuration : @Beanméthodes ed qui renvoient des instances

Pour spécifier que Cls[19659020] doit être instancié en tant que bean au moment de l'exécution, annotez une méthode qui renvoie une instance de Cls avec @Beanet placez cette méthode annotée dans une classe qui est elle-même annotée avec [19659019]@Configuration :

@Configuration
Configuration de la classe publique
{
     @Haricot
     public Cls createABeanWrappingAClsInstance(Object args) { return new Cls(args); }
}

Deuxième méthode de configuration : utilisez @Component et @ComponentScan

Une autre façon de spécifier qu'une classe Cls doit être instanciée comme un bean à runtime consiste à annoter la déclaration de classe de Cls (c'est-à-dire classe publique Cls) avec @Componenttout en annotant également une autre classe, par exemple Configc'est-à-dire "au niveau ou au-dessus" du niveau de Cls dans la hiérarchie des répertoires avec @Configuration et @ComponentScan :

 @Configuration
@ComponentScan
/* La configuration doit être égale ou supérieure à Cls dans la hiérarchie des répertoires. */
Configuration de la classe publique {}

@Composant
public class Cls { ... }

(Lorsque vous créerez ultérieurement un ApplicationContext dans la méthode main() de votre application, vous devrez passer ApplicationContext .class au constructeur ApplicationContext.Mais, sisi vous utilisez Spring Boot, la classe contenant la méthode main() est déjà secrètement annotée avec @Configuration et @ComponentScanvous n'avez donc rien d'autre à faire que d'annoter Cls avec @Component).

Plus précisément, l'utilisation de @ComponentScan de cette manière spécifie que, lors de l'exécution, si une classe "au niveau ou en dessous" du niveau de Cls dans la hiérarchie des répertoires est annotée par [19659019]@Component ou une annotation méta-annotée par @Component (c'est-à-dire par @Service@Repositoryou@ Controller), alors cette classe sera utilisée pour construire un bean Spring.

Sidenote : annotation "héritage" dans Spring

Comme indiqué dans cette réponse Stack OverflowSpring Framework's AnnotationUtils classe[19650] ] a une méthode qui teste si une annotation est égale ou est annotée avec une autre annotation. Je fais une supposition éclairée que Spring utilise ce type de test d'héritage pour les annotations partout. 19659019]@Contrôleur

@Service@Repository et @Controller sont similaires en ce sens qu'ils sont tous méta-annotés par @Component. Quelles sont les différences ?

Lectures supplémentaires : @Component vs. @Service vs. @Repository vs. @Controller@Component vs. @Bean .

Nous savons maintenant comment configurer les beans Spring, mais nous ne savons pas encore comment injecter des dépendances Spring beans dans d'autres beans Spring. Nous décrivons comment procéder dans cette section.

Bien qu'avant de décrire comment procéder, il y a un peu plus de connaissances préalables que nous devrions couvrir.

Plus de connaissances préalables

Convention : "définition du haricot"[19659109]Pour la suite de ce document, le terme définition de bean fera référence à une méthode annotée par @Bean qui renvoie une instance d'objet ou une classe annotée par @Component[19659026].

Portées de bean

Chaque définition de bean a une «portée» associée.

La portée par défaut (et la plus importante) est singleton. Si un bean a une portée singleton toutes les références à ce bean accèdent au même objet Java. la portée singleton est utilisée pour réaliser le partage des dépendances, ce qui, si vous vous souvenez de la section "Injection de dépendances" ci-dessus, est l'un des principaux avantages de l'utilisation d'un conteneur IoC.

La deuxième portée la plus importante est [19659019] prototype . Si un bean est de portée prototype différentes références à ce bean sont des références à différents objets Java.

Les quatre autres champs d'application, requestsessionapplication et websocketne peuvent être utilisés que dans un contexte d'application conscient » et sont moins couramment utilisés. Ne vous inquiétez pas pour ceux-ci.

Terminologie : "plain old Java objects" ("POJOs")

Une "plain old Java class" est une classe qui ne dépend pas d'un framework d'application tel que Printemps. Fondamentalement, étant donné que la plupart des fonctionnalités Spring sont gérées avec des annotations, une ancienne classe Java ordinaire est une classe sans aucune annotation Spring.

Malheureusement, les gens disent "plain old Java object" au lieu de "plain old Java class", nous parlons donc de POJO au lieu de POJC.

Les POJO sont souvent utilisés dans les applications Spring en combinaison avec des non-POJO pour représenter des objets "plus concrets" (tels qu'un Employéetc.).

Lecture supplémentaire : http : //www.shaunabram.com/beans-vs-pojos/.

Implémentation de l'injection de dépendance quelque peu manuelle

Maintenant, nous sommes prêts à utiliser Spring Framework pour implémenter le modèle de conception d'injection de dépendance.[19659002]Supposons que nous ayons configuré un bean Spring nommé Cls1 qui fait référence à un bean Spring Cls2 :

@Component
classe publique Cls1
{
     privé Cls2 cls2 ;
     public Cls2 getCls2() { return cls2; }
     public void setCls2(Cls2 cls2) { this.cls2 = cls2;}
}
​
@Composant
public class Cls2 { ... }

Nous voulons injecter une instance de Cls2 dans notre bean Cls1 au moment de l'exécution. Pour ce faire, nous avons besoin d'une référence au conteneur Spring IoC. Étant donné que ApplicationContext étend BeanFactoryet a donc plus de fonctionnalités, ApplicationContext doit être utilisé dans la plupart des situations.

Nous effectuons l'injection de dépendances en utilisant ApplicationContext comme suit :

application de classe publique
{
public static void main(String[] args)
{
/*  est le package dans lequel rechercher les classes @Configuration et dans lequel effectuer @ComponentScan. Par example,
        pourrait être "com.perficient.techbootcamp.*" */
ApplicationContext ctx = nouvelle annotationConfigApplicationContext("");

/* Ce qui suit suppose qu'une classe nommée Cls a été configurée en tant que bean (rappelez-vous, ceci est fait
en utilisant @Component et @ComponentScan ou en utilisant @Bean). */
Cls1 cls1 = ctx.getBean(Cls1.class);

/* Effectuer l'injection de dépendance : injecter une instance de cls2 dans le bean cls1. */
Cls2 cls2 = nouveau Cls2();
cls1.setCls2(cls2);
}
}

Le code ci-dessus est adapté de l'article de Macro Behler.

Implémentation de l'injection de dépendance avec @Autowired

Dans Spring Framework, on utilise généralement des annotations qui exécutent l'effet de l'injection de dépendance ci-dessus dans les coulisses. Plus précisément, on utilise l'annotation @Autowired . Lorsque @Autowired est présent sur le champ d'un bean, une instance du type de ce champ sera injectée dans ce champ lors de l'exécution.

Donc, si nous voulons reproduire la fonctionnalité ci-dessus, nous écrirons ce qui suit :

@Composant
classe publique Cls2 { ... }
​
@Composant
classe publique Cls1
{
     @Autowired
     privé Cls2 cls2 ;

     public Cls2 getCls2() { return cls2; }
     // Remarquez, aucun setter n'est nécessaire.
}
​
Demande de classe publique
{
public static void main(String[] args)
{
ApplicationContext ctx = nouvelle annotationConfigApplicationContext("");

/* Le code ci-dessous a été commenté car il n'est pas nécessaire.
L'annotation @Autowired ci-dessus indique à Spring Framework d'injecter
une référence au bean Cls2 dans le bean Cls1 au moment de l'exécution. */

// Cls1 cls1 = ctx.getBean(Cls1.class);
// Cls2 cls2 = new Cls2();
// cls1.setCls2(cls2);
}
}

Injection de champ avec @Autowired

Vous pouvez vous demander comment il est possible d'injecter une instance de Cls2 dans cls1 lorsque Cls1 n'a pas de méthode setCls2() . Après y avoir réfléchi une seconde, vous pourriez soupçonner que l'injection est effectuée en utilisant le constructeur de Cls1. Ce n'est en fait pas le cas. (Dans le code ci-dessus, Cls1 n'a pas de constructeur with-args !). Lorsque @Autowired annote le champ d'un bean, alors, au moment de l'exécution, le conteneur IoC utilise cette technique de réflexion Java pour modifier le champ, même s'il est privé.[19659002]Placer @Autowired sur un champ constitue donc une injection de champ.

Utiliser @Autowired sur des champs est une mauvaise pratique

Selon [19]659259 cet articlel'utilisation de l'injection de champ est une mauvaise pratique car elle vous interdit de marquer les champs comme final . (Vous voulez pouvoir marquer les champs comme final le cas échéant, car cela vous empêche d'entrer dans une situation de dépendance circulaire).

Autres raisons pour lesquelles l'injection de champ est mauvaise : https:/ /dzone.com/articles/spring-di-patterns-the-good-the-bad-and-the-ugly.

Utilisation de @Autowired sur les constructeurs et passeurs

@Autowired peut également être utilisé sur des constructeurs ou des setters pour injecter un paramètre dans un constructeur ou un setter au moment de l'exécution.

L'annotation @Qualifier

Parce qu'un bean peut avoir un champ @Autowired dont le type est une interface, et parce que plusieurs classes peuvent implémenter la même interface, il peut être nécessaire de spécifier quelle implémentation de l'interface est censée être injectée en dépendance. Cela se fait avec l'annotation @Qualifier comme suit :

public interface Intf { ... }

@Qualifier("impl1")
@Composant
la classe publique Impl1 étend Intf { ... }
​
@Qualifier("impl2")
@Composant
la classe publique Impl2 étend Intf { ... }
​
classe publique Cls
{
@Autowired
@Qualifier("impl1")
Cls1 privé cls1Instance ; // lors de l'exécution, cls1Instance sera défini sur une instance Cls1

     @Autowired
@Qualifier("impl2")
Cls2 privé cls2Instance ; // lors de l'exécution, cls1Instance sera défini sur une instance Cls1
}

Voici les spécificités de la façon dont les noms de champs sont mis en correspondance avec les noms de bean :

  • Définissez le qualifier-name d'une définition de bean ou d'un champ comme étant : (1) l'argument du @Qualifier annotation attachée à ladite définition ou champ de bean, si la définition ou le champ de bean est effectivement annoté avec @Qualifieret (2) le nom de la classe associée à la définition de bean , si la définition ou le champ du bean n'est pas annoté avec @Qualifier.

  • Lorsqu'aucune annotation @Qualifier n'est présente sur un champ, alors la classe dont le nom de qualificateur indépendant de la casse est égal au nom indépendant de la casse du champ correspond à la dépendance injectée dans le champ. ("Case agnostic" signifie "ignorer la casse").

Ceci conclut mon introduction à Spring Framework for Java. J'espère que c'est utile !

À propos de l'auteur

Ross Grogan-Kaylor est consultant technique associé au bureau de Perficient à Minneapolis. Il aime s'engager avec des modèles structurels dans la syntaxe et dans les idées de haut niveau du développement de logiciels. f.fbq)return;n=f.fbq=function(){n.callMethod ?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(fenêtre,
document,'script','https://connect.facebook.net/en_US/fbevents.js');

fbq('init', '911436665572720');
fbq('track', "PageView");




Source link

janvier 20, 2022 Java