Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mborne/spring-ioc-principe
https://github.com/mborne/spring-ioc-principe
Last synced: 26 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/mborne/spring-ioc-principe
- Owner: mborne
- Created: 2016-01-20T06:58:10.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2023-12-06T22:41:14.000Z (about 1 year ago)
- Last Synced: 2024-10-19T00:57:32.418Z (3 months ago)
- Language: Java
- Size: 31.3 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Illustration du principe d'inversion de contrôle
## Description
Ce projet est une annexe du [cours sur patrons de conception](https://mborne.github.io/cours-patron-conception/) qui illustre le concept d'injection de dépendance avec Spring.
## Problème
On veut pouvoir **automatiser et configurer la construction d'un ensemble d'objets présentant des dépendances** à l'échelle d'une application.
## Solution : Injection de dépendance
* Laisser le framework appeler les constructeurs et aux accesseurs qui établissent les relations entre les objets.
* Déléguer la construction des objets et la définition des relations à un framework## Exemple (ce code)
On dispose d'un ensemble de classes :
![Diagramme de classe](uml/exemple.png)
On veut créer une application avec une pile de message (identifiée par "queue") partagée par :
* Un Thread de production de message ([Producer](src/main/java/org/acme/ioc/Producer.java)) qui **empile des messages à traiter** et s'arrête
* Un Thread de consommation ([Consumer](src/main/java/org/acme/ioc/Consumer.java)) des messages de la "queue" qui se contente d'**afficher ces messages**.
* Une IHM ([Window]([Consumer](src/main/java/org/acme/ioc/Window.java))) qui permet à l'utilisateur d'**ajouter manuellement des messages à la pile**.Mieux : On veut démarrer les Thread au démarrage de l'application.
## Mise en oeuvre avec Spring
Un contexte spring [ApplicationContext](https://www.baeldung.com/spring-application-context) est initialisé à l'aide d'un fichier XML qui fait partie des ressources du programme :
```java
// Initialisation du contexte spring
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("/spring/beans.xml");
```Ce fichier XML [/src/main/resources/spring/beans.xml](src/main/resources/spring/beans.xml) est commenté. Il contient les informations nécessaires à la **construction des objets (inversion de contrôle)** et à la **définition des relations entre ces objets (injection de dépendances)**.
## Démonstration
* `mvn package exec:java`
* Suivre les logs dans la console
* Jouer avec l'interface(Le main est dans la classe [Application](src/main/java/org/acme/ioc/Application.java))
## Comment ça marche?
L'initialisation des objets va s'appuyer massivement sur les concepts d'introspection et de réflexion supportés par le langage Java.
### Création de l'objet "queue"
```xml
```
* Récupération de la classe `java.util.concurrent.ArrayBlockingQueue` par son nom
* Récupération du constructeur `ArrayBlockingQueue(int)`
* Appel du constructeur avec un entier de valeur 5
* Stockage du bean dans une `beans: Map`### Création d'un objet "consumer" de type "Consumer"
```xml
```
* Construction d'une instance de la classe `org.acme.ioc.Consumer`
* Passage d'une référence au bean "queue" par appel de la méthode `setQueue`
* Appel d'une méthode d'initialisation `start` (Consumer est un Thread)Remarque :
* Par défaut, le framework recherche un constructeur sans paramètre.
* [Un bean doit normalement posséder un constructeur sans paramètre](http://www.jmdoudoux.fr/java/dej/chap-javabean.htm).
* `ApplicationContext` peut être manipulé par programmation, par exemple pour récupérer
les beans par leur nom.```java
Window window = (Window) context.getBean("window");
window.setVisible(true);
```## Intérêt au niveau de l'application
* L'initialisation des objets partagés par plusieurs classes est simplifiée (moins de risque de "singletonite")
* Le **paramétrage de l'application est géré de manière cohérente** au niveau framework (voir [docs.spring.io - Externalized Configuration](https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-external-config.html)).
* L'ajout d'un paramètre est indolore (ex : ajout du support d'un proxy sortant dans un "httpClient")
* L'application peut être construite par assemblage de modules.## Allez plus loin
* Comprendre la notion de [scope](http://www.tutorialspoint.com/spring/spring_bean_scopes.htm) (par défaut, spring initialise des singletons mais il est par possible d'initialiser des objets rattachés aux sessions des requêtes HTTP)
* Consulter la documentation de Spring : [Vue d'ensemble de spring](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/overview.html#overview-modules)## Variantes d'implémentation de IoC
### Variante en Java avec des annotations (Spring moderne)
Les versions récentes de Spring s'appuie sur des [annotations et les fonctionnalités d'introspection associées](https://jenkov.com/tutorials/java-reflection/annotations.html) plutôt que sur des fichiers XML (voir [spring.io - Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) ). Cet exemple conserve volontairement la version XML qui a le mérite d'être explicite.
### Variante légère en Java avec ServiceLoader
L'API java intègre un [ServiceLoader](https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html) qui permet de créer et récupérer des instances implémentant une interface.
Les instances à créer pour une interface `org.acme.Format` sont listées dans un fichier `main/resources/META-INF/services/org.acme.Format` :
```
org.acme.format.WKT
org.acme.format.WKB
```Nous soulignerons que :
* Les classes doivent impérativement offrir un **constructeur par défaut**
* Ce principe est souvent utilisé pour la production de système de plugin (sans dépendance à un framework particulier)Exemple : [Plugin pour la lecture des shapefile dans Geotools](https://github.com/geotools/geotools/blob/master/modules/plugin/shapefile/src/main/resources/META-INF/services/org.geotools.data.DataStoreFactorySpi).
* Attention à bien concaténer ces fichiers si vous formez un jar qui embarque un ensemble de dépendances!
## Variante en PHP
Le framework Symfony se repose massivement sur le concept d'injection de dépendances.