JavaRush /Blog Java /Random-FR /Le printemps est pour les paresseux. Fondamentaux, concep...
Стас Пасинков
Niveau 26
Киев

Le printemps est pour les paresseux. Fondamentaux, concepts de base et exemples avec code. Partie 2

Publié dans le groupe Random-FR
Dans le dernier article , j'ai expliqué en un mot ce qu'est le printemps, ce que sont les bacs et le contexte. Il est maintenant temps d'essayer comment tout cela fonctionne. Le printemps est pour les paresseux.  Fondamentaux, concepts de base et exemples avec code.  Partie 2 - 1Je le ferai moi-même dans Intellij Idea Enterprise Edition. Mais tous mes exemples devraient également fonctionner dans l'édition gratuite Intellij Idea Community. Juste si vous voyez sur les captures d'écran que j'ai une sorte de fenêtre que vous n'avez pas, ne vous inquiétez pas, ce n'est pas critique pour ce projet :) Tout d'abord, créons un projet Maven vide. J'ai montré comment faire cela dans l'article (lisez jusqu'à ce que les mots " Il est temps de transformer notre projet maven en projet Web. ", Après cela, il montre déjà comment créer un projet Web, et nous n'en avons pas besoin maintenant) Créons-le dans le dossier src/main /java est un package (dans mon cas, je l'ai appelé «ru.javarush.info.fatfaggy.animals », vous pouvez le nommer comme vous voulez, n'oubliez pas de le remplacer par votre nom aux bons endroits). Et créons une classe Maindans laquelle nous créerons une méthode
public static void main(String[] args) {
    ...
}
Ensuite, ouvrez le fichier pom.xml et ajoutez-y une section dependencies. Maintenant, nous allons dans le référentiel Maven et recherchons le contexte Spring de la dernière version stable, et collons ce que nous avons dans la section dependencies. J'ai décrit ce processus un peu plus en détail dans cet article (voir la section « Connecter les dépendances dans Maven »). Ensuite, Maven lui-même trouvera et téléchargera les dépendances nécessaires, et à la fin vous devriez obtenir quelque chose comme ceci :
Le printemps est pour les paresseux.  Fondamentaux, concepts de base et exemples avec code.  Partie 2 - 2
Dans la fenêtre de gauche, vous pouvez voir la structure du projet avec le package et la classe Main. La fenêtre du milieu montre à quoi ressemble mon pom.xml. J'y ai également ajouté une section de propriétés dans laquelle j'ai indiqué à Maven quelle version de Java j'utilisais dans le code source et dans quelle version compiler. C'est juste pour que je n'aie pas l'idée d'un avertissement au démarrage indiquant qu'une ancienne version de Java est utilisée. Vous pouvez le faire, vous ne pouvez pas) Dans la fenêtre de droite - vous pouvez voir que même si nous n'avons connecté que le contexte Spring - il a automatiquement ajouté le noyau, les beans, l'aop et l'expression. Il était possible de connecter chaque module séparément, en enregistrant une dépendance pour chacun dans la mémoire avec une indication explicite de la version, mais pour l'instant nous sommes satisfaits de l'option telle qu'elle est actuellement. Créons maintenant un package entities(entités) et créons-y 3 classes : Cat, Dog, Parrot. Laissez chaque animal avoir un nom ( private String name, vous pouvez y coder en dur certaines valeurs), et les getters/setters sont publics. Allez maintenant dans la classe Mainet main()écrivez quelque chose comme ceci dans la méthode :
public static void main(String[] args) {
	// create an empty spring context that will search for its beans by annotations in the specified package
	ApplicationContext context =
		new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.entities");

	Cat cat = context.getBean(Cat.class);
	Dog dog = (Dog) context.getBean("dog");
	Parrot parrot = context.getBean("parrot-kesha", Parrot.class);

	System.out.println(cat.getName());
	System.out.println(dog.getName());
	System.out.println(parrot.getName());
}
Tout d'abord, nous créons un objet contextuel et, dans le constructeur, nous lui donnons le nom du package qui doit être analysé pour détecter la présence de beans. Autrement dit, Spring parcourra ce package et essaiera de trouver des classes marquées par des annotations spéciales permettant à Spring de savoir qu'il s'agit d'un bean. Après quoi il crée des objets de ces classes et les place dans son contexte. Après quoi nous obtenons un chat de ce contexte. Lorsque nous nous tournons vers l'objet contextuel, nous lui demandons de nous donner un bean (objet) et d'indiquer de quelle classe d'objet nous avons besoin (ici, d'ailleurs, vous pouvez spécifier non seulement des classes, mais aussi des interfaces). Après quoi Spring nous renvoie un objet de cette classe, que nous enregistrons dans une variable. Ensuite, nous demandons à Spring de nous procurer un haricot appelé « chien ». Lorsque Spring crée un objet de classe, Dogil lui donne un nom standard (si le nom du bean en cours de création n'est pas explicitement spécifié), qui est le nom de la classe de l'objet, uniquement avec une petite lettre. Par conséquent, puisque notre classe s'appelle Dog, le nom d'un tel haricot sera « chien ». Si nous avions un objet là-bas BufferedReader, Spring lui donnerait le nom par défaut « bufferedReader ». Et comme dans ce cas (en Java), il n'y a pas de certitude exacte quant à la classe d'un tel objet, il en renvoie simplement une certaine Object, que nous convertissons ensuite manuellement dans le type dont nous avons besoin Dog. L'option avec une indication explicite de la classe est plus pratique. Eh bien, dans le troisième cas, nous obtenons un bean par classe et par nom. Il peut simplement y avoir une situation où dans le contexte il y aura plusieurs beans d'une même classe, et afin d'indiquer de quel bean particulier nous avons besoin, nous indiquons son nom. Puisque nous avons également clairement indiqué la classe ici, nous n'avons plus besoin de lancer de casting. Important!S'il s'avère que Spring trouve plusieurs beans selon les exigences que nous lui avons spécifiées, il ne pourra pas déterminer quel bean nous donner et lèvera une exception. Essayez donc de lui indiquer le plus précisément possible de quelle poubelle vous avez besoin, afin que de telles situations ne se produisent pas. Si Spring ne trouve pas un seul bean dans son contexte selon vos conditions, il lèvera également une exception. Eh bien, nous affichons ensuite simplement les noms de nos animaux sur l'écran pour nous assurer que ce sont bien exactement les objets dont nous avons besoin. Mais si nous exécutons le programme maintenant, nous verrons que Spring jure qu'il ne peut pas trouver les animaux dont nous avons besoin dans son contexte. Cela s'est produit parce qu'il n'a pas créé ces haricots. Comme je l'ai déjà dit, lorsque Spring analyse les classes, il y recherche « ses » annotations Spring. Et s’il ne le trouve pas, alors il ne perçoit pas ces classes comme celles dont il a besoin de créer les beans. Pour résoudre ce problème, ajoutez simplement une annotation @Componentdevant la classe dans nos classes d'animaux.
@Component
public class Cat {
	private String name = "Barsik";
	...
}
Mais ce n'est pas tout. Si nous devons indiquer explicitement à Spring que le bean de cette classe doit avoir un nom spécifique, ce nom peut être indiqué entre parenthèses après l'annotation. Par exemple, pour que Spring donne le nom dont nous avons besoin parrot-keshaau bac à perroquets, à partir duquel nous mainrecevrons plus tard ce perroquet, nous devons faire quelque chose comme ceci :
@Component("parrot-kesha")
public class Parrot {
	private String name = "Kesha";
	...
}
C'est tout l'intérêt de la configuration automatique . Vous écrivez vos classes, les marquez avec les annotations nécessaires et indiquez à Spring un package avec vos classes, à travers lequel il passe, recherche des annotations et crée des objets de ces classes. À propos, Spring recherchera non seulement les annotations @Component, mais également toutes les autres annotations héritées de celle-ci. Par exemple, @Controller, @RestController, @Service, @Repositoryet d'autres, que nous rencontrerons dans d'autres articles. Essayons maintenant de faire la même chose, mais en utilisant la configuration Java . Tout d’abord, supprimons les annotations @Componentde nos classes. Pour compliquer la tâche, imaginons qu'il ne s'agit pas de nos propres classes auto-écrites, que nous pouvons facilement modifier, ajouter quelque chose, y compris des annotations. C’est comme si ces cours étaient rangés dans une bibliothèque. Dans ce cas, nous ne pouvons en aucun cas modifier ces classes pour qu'elles soient acceptées par Spring. Mais nous avons besoin d'objets de ces classes ! Ici, nous aurons besoin de la configuration Java pour créer de tels objets. Pour commencer, créons un package, par exemple configs, et dedans - une classe Java standard, par exemple, MyConfiget marquons-le avec une annotation@Configuration
@Configuration
public class MyConfig {
}
Nous devons maintenant modifier légèrement main()la façon dont nous créons le contexte dans la méthode. Nous pouvons soit y spécifier directement notre classe avec configuration :
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class);
Si nous avons plusieurs classes différentes dans lesquelles nous créons des beans et que nous souhaitons en connecter plusieurs à la fois, nous les indiquons simplement séparés par des virgules :
ApplicationContext context =
	new AnnotationConfigApplicationContext(MyConfig.class, MyAnotherConfig.class);
Eh bien, si nous en avons trop et que nous voulons les connecter tous en même temps, nous indiquons simplement ici le nom du package dans lequel nous les avons :
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.configs");
Dans ce cas, Spring parcourra ce package et trouvera toutes les classes marquées de l'annotation @Configuration. Eh bien, dans le cas où nous avons un très gros programme où les configurations sont divisées en différents packages, nous indiquons simplement les noms des packages avec les configurations séparées par des virgules :
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals.database.configs",
		"ru.javarush.info.fatfaggy.animals.root.configs",
		"ru.javarush.info.fatfaggy.animals.web.configs");
Eh bien, ou le nom d'un package plus commun à tous :
ApplicationContext context =
	new AnnotationConfigApplicationContext("ru.javarush.info.fatfaggy.animals");
Vous pouvez le faire comme vous le souhaitez, mais il me semble que la toute première option, où vous spécifiez simplement une classe avec des configurations, conviendra le mieux à notre programme. Lors de la création d'un contexte, Spring recherchera les classes marquées par l'annotation @Configurationet créera lui-même des objets de ces classes. Après quoi, il essaiera d'appeler des méthodes dans ces classes marquées de l'annotation @Bean, ce qui signifie que ces méthodes renverront des beans (objets) qu'il a déjà placés dans son contexte. Eh bien, créons maintenant des haricots chat, chien et perroquet dans notre classe avec une configuration Java. Cela se fait tout simplement :
@Bean
public Cat getCat() {
	return new Cat();
}
Il s'avère que nous avons créé manuellement notre chat nous-mêmes et l'avons donné à Spring, et il a déjà placé cet objet dans son contexte. Puisque nous n’avons pas explicitement spécifié le nom de notre bean, Spring donnera au bean le même nom que le nom de la méthode. Dans notre cas, la fève du chat portera le nom " getCat". Mais comme dans main-e nous obtenons toujours le chat non pas par son nom, mais par classe, alors dans ce cas, le nom de cette poubelle n'a pas d'importance pour nous. Faites un haricot avec un chien de la même manière, mais gardez à l'esprit que Spring nommera un tel haricot par le nom de la méthode. Pour nommer explicitement notre bean avec le perroquet, indiquez simplement son nom entre parenthèses après l'annotation @Bean:
@Bean("parrot-kesha")
public Object weNeedMoreParrots() {
	return new Parrot();
}
Comme vous pouvez le voir, j'ai indiqué ici le type de valeur de retour Objectet j'ai appelé la méthode n'importe quoi. Cela n'affecte en rien le nom du bean car nous le définissons explicitement ici. Mais il est préférable d'indiquer le type de valeur de retour et le nom de la méthode non pas à l'improviste, mais plus ou moins clairement. Juste même pour vous-même, lorsque vous ouvrirez ce projet dans un an. :) Considérons maintenant une situation dans laquelle pour créer un bean, nous devons utiliser un autre bean . Par exemple, nous voulons que le nom du chat dans le chat soit composé du nom du perroquet et de la chaîne "-killer". Aucun problème!
@Bean
public Cat getCat(Parrot parrot) {
	Cat cat = new Cat();
	cat.setName(parrot.getName() + "-killer");
	return cat;
}
Ici, Spring verra qu'avant de créer ce bean, il devra transférer ici le bean perroquet déjà créé. Par conséquent, il construira une chaîne d'appels à nos méthodes pour que la méthode de création d'un perroquet soit appelée en premier, puis transmettra ce perroquet à la méthode de création d'un chat. C'est là que fonctionnait ce qu'on appelle l'injection de dépendances : Spring lui-même a transmis le bean perroquet requis à notre méthode. Si l'idée se plaint d'une variable parrot, n'oubliez pas de changer le type de retour dans la méthode de création d'un perroquet de Objectà Parrot. De plus, la configuration Java vous permet d'exécuter absolument n'importe quel code Java dans les méthodes de création de beans. Vous pouvez vraiment tout faire : créer d'autres objets auxiliaires, appeler d'autres méthodes, même celles qui ne sont pas marquées d'annotations Spring, créer des boucles, des conditions - tout ce qui vous vient à l'esprit ! Tout cela ne peut pas être réalisé en utilisant la configuration automatique, et encore moins en utilisant les configurations XML. Examinons maintenant un problème plus amusant. Avec polymorphisme et interfaces :) Créons une interface WeekDayet créons 7 classes qui implémenteraient cette interface : Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. Créons une méthode dans l'interface String getWeekDayName()qui renverrait le nom du jour de la semaine de la classe correspondante. Autrement dit, la classe Mondayrenverrait " monday", etc. Disons que la tâche lors du lancement de notre application est de placer un bean dans le contexte qui correspondrait au jour de la semaine en cours. Pas tous les beans de toutes les classes qui implémentent WeekDayl'interface, mais seulement celui dont nous avons besoin. Cela peut être fait quelque chose comme ceci :
@Bean
public WeekDay getDay() {
	DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
	switch (dayOfWeek) {
		case MONDAY: return new Monday();
		case TUESDAY: return new Tuesday();
		case WEDNESDAY: return new Wednesday();
		case THURSDAY: return new Thursday();
		case FRIDAY: return new Friday();
		case SATURDAY: return new Saturday();
		default: return new Sunday();
	}
}
Ici, le type de valeur de retour est notre interface, et la méthode renvoie des objets réels des classes d'implémentation de l'interface en fonction du jour de la semaine en cours. Maintenant, dans la méthode main(), nous pouvons faire ceci :
WeekDay weekDay = context.getBean(WeekDay.class);
System.out.println("It's " + weekDay.getWeekDayName() + " today!");
Il m'a dit qu'aujourd'hui c'est dimanche :) Je suis sûr que si j'exécute le programme demain, un objet complètement différent apparaîtra dans le contexte. Veuillez noter qu'ici nous obtenons le bean simplement par l'interface : context.getBean(WeekDay.class). Spring examinera son contexte pour voir lequel de ses beans implémente une telle interface et la renverra. Eh bien, il s'avère qu'il WeekDayy a un objet de type dans une variable de type Sunday, et le polymorphisme, déjà familier à nous tous, commence lorsque vous travaillez avec cette variable. :) Et quelques mots sur l'approche combinée , où certains beans sont créés par Spring lui-même, en analysant les packages pour détecter la présence de classes avec une annotation @Component, et certains autres beans sont créés à l'aide de la configuration Java. Pour ce faire, revenons à la version originale, lorsque les classes Cat, Doget Parrotétaient marquées d'une annotation @Component. Disons que nous souhaitons créer des bacs pour nos animaux en utilisant la numérisation automatique du colis entitiesd'ici le printemps, mais que nous créons un bac avec le jour de la semaine comme nous venons de le faire. Tout ce que vous avez à faire est d'ajouter au niveau de la classe MyConfig, que nous spécifions lors de la création du contexte dans mainla -ème annotation @ComponentScan, et d'indiquer entre parenthèses le package qui doit être analysé et les beans des classes nécessaires créés automatiquement :
@Configuration
@ComponentScan("ru.javarush.info.fatfaggy.animals.entities")
public class MyConfig {
	@Bean
	public WeekDay getDay() {
		DayOfWeek dayOfWeek = LocalDate.now().getDayOfWeek();
		switch (dayOfWeek) {
			case MONDAY: return new Monday();
			case TUESDAY: return new Tuesday();
			case WEDNESDAY: return new Wednesday();
			case THURSDAY: return new Thursday();
			case FRIDAY: return new Friday();
			case SATURDAY: return new Saturday();
			default: return new Sunday();
		}
	}
}
Il s'avère que lors de la création d'un contexte, Spring voit qu'il doit traiter la classe MyConfig. Il y entre et voit qu'il doit analyser le package " ru.javarush.info.fatfaggy.animals.entities" et créer des beans de ces classes, après quoi il exécute la méthode getDay()de la classe MyConfiget ajoute le type bean WeekDayà son contexte. Dans la méthode, main()nous avons désormais accès à tous les beans dont nous avons besoin : à la fois les objets animaux et le bean avec le jour de la semaine. Comment s'assurer que Spring récupère également certaines configurations XML - recherchez-les vous-même sur Internet si nécessaire :) Résumé :
  • essayez d'utiliser la configuration automatique ;
  • lors de la configuration automatique, nous indiquons le nom du package contenant les classes dont les beans doivent être créés ;
  • ces classes sont marquées d'une annotation@Component;
  • le printemps traverse toutes ces classes, crée leurs objets et les place dans le contexte ;
  • si la configuration automatique ne nous convient pas pour une raison quelconque, nous utilisons la configuration Java ;
  • dans ce cas, nous créons une classe Java standard dont les méthodes renverront les objets dont nous avons besoin, et marquons une telle classe avec une annotation @Configurationau cas où nous analyserions l'intégralité du package plutôt que de spécifier une classe spécifique avec une configuration lors de la création du contexte ;
  • les méthodes de cette classe qui renvoient des beans sont marquées de l'annotation @Bean;
  • si nous voulons activer l'analyse automatique lors de l'utilisation de la configuration Java, nous utilisons l'annotation @ComponentScan.
Si rien n'est clair, essayez de lire cet article dans quelques jours. Eh bien, ou si vous êtes aux premiers niveaux de Javarash, alors il est peut-être un peu tôt pour apprendre le printemps. Vous pourrez toujours revenir sur cet article un peu plus tard, lorsque vous vous sentirez plus à l'aise dans la programmation en Java. Si tout est clair, vous pouvez essayer de transférer certains de vos projets favoris vers Spring :) Si quelque chose est clair, mais que quelque chose ne l'est pas tellement, veuillez commenter :) Il y a aussi des suggestions et des commentaires si je suis allé quelque part ou si j'ai écrit quelque chose de stupide ) Dans le prochain article, nous approfondirons spring-web-mvc et créerons une application Web simple en utilisant Spring.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION