The Spring IoC container is at the core of the Spring Framework. The container will create the objects, wire them together, configure them, and manage their complete life cycle from creation till destruction. The Spring container uses dependency injection (DI) to manage the components that make up an application.
2. L’Injection de Dépendances
• A la base, il s’agit simplement d’injecter un objet dans un Autre
public class TodosServiceImpl {
private UserService userService;
}
2
userService doit être injecté
3. L’injection par setter
• 1ère méthode, «classique» : l’injection par setter
• ○ Utilise la convention Java Bean
public class TodosServiceImpl {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
}
3
Spring va appeler cette méthode
4. L’injection par constructeur
• 2Ème méthode, relativement populaire : utiliser le constructeur de l’objet
public class TodosServiceImpl {
private UserService userService;
public TodosServiceImpl(UserService userService) {
this.userService = userService;
}
}
4
Spring va construire l’objet correctement
5. L’injection dans un champ
• 3ème méthode : Spring injecte directement dans le champ
oMéthode «magique» : en fait les champs «private» en Java peuvent être modifiés (si
vous venez d’avoir un cours sur Java, on vous a menti)
oDe plus en plus populaire car la méthode la plus simple
public class TodosServiceImpl {
private UserService userService;
}
5
Spring injecte directement dans le champ
7. Exigences Fonctionnelles
• Satisfaire les besoins fonctionnels (métiers) de l’entreprises
Exigences Techniques
• Performances : l’application doit être performante
Temps de réponse
Problème de montée en charge : Vers une architecture Distribuée scalable
Equilibrage de charges et Tolérances aux panes
• Maintenance : l’application doit être facile à maintenir
Une application doit évoluer dans le temps
L’application doit être fermée à la modification et ouverte à l’extension
• Sécurité : L’application doit prévoir des solutions pour toutes les failles de sécurités
• Persistances des données dans des SGBD appropriés, Gestion des Transactions
• Créer différents types de clients pour accéder à l’application : Web, Mobile, Desktop,
Exigences financières : Le coût du logiciel doit respecter les contraites budgétaires
Exigences d’un projet informatique
7
8. Constat
Il est très difficile de développer un système logiciel qui respecte ces exigences sans
utiliser l’expérience des autres :
◦ Bâtir l’application sur une architecture d’entreprise:
JEE
◦ Framework pour l’Inversion de contrôle:
Permettre au développeur de s’occuper uniquement du code métier
(Exigences fonctionnelles) et c’est le Framework qui s’occupe du code
technique (Exigences Techniques)
Spring (Conteneur léger)
EJB (Conteneur lourd)
◦ Frameworks :
Mapping objet relationnel (ORM ) : JPA, Hibernate, Toplink, …
Applications Web : Struts, JSF, SpringMVC
◦ Middlewares :
RMI, CORBA : Applications distribuées
Web Services :
JAXWS pour Web services SOAP
JAXRS pour les Web services RESTful
Communication asynchrone entre les application :
JMS :
AMQP :
8
9. Exemple : sans utiliser d’inversion de contrôle
Exemple : sans utiliser d’inversion de contrôle
public void virement(int c1, int c2, double mt) {
/* Création d’une transaction */
EntityTransaction transaction=entityManager.getTransaction();
/* Démarrer la transaction */
transaction.begin();
try {
/* Code métier */
retirer(c1,mt);
verser(c2,mt);
/* Valider la transaction */
transaction.commit();
} catch (Exception e) {
/* Annuler la transaction en cas d’exception */
transaction.rollback();
e.printStackTrace();
}
}
Code Technique
Code Technique
Code Métier
9
10. Exemple : sans utiliser d’inversion de contrôle
Code Métier
@Transactional
public void virement(int c1, int c2, double mt) {
retirer(c1,mt);
verser(c2,mt);
}
Ici, avec l’annotation @Transactional, nous avons
délégué la gestion des transactions au conteneur
Spring IOC
10
11. Quand une classe A est lié à une classe B, on dit que la classe A est fortement couplée à la
classe B.
La classe A ne peut fonctionner qu’en présence de la classe B.
Si une nouvelle version de la classe B (soit B2), est crée, on est obligé de modifier dans la
classe A.
Modifier une classe implique:
◦ Il faut disposer du code source.
◦ Il faut recompiler, déployer et distribuer la nouvelle application aux clients.
◦ Ce qui engendre un cauchemar au niveau de la maintenance de l’application
Couplage fort
A
b:B
Calcul(): double
B
11
12. Couplage Faible
IA
Calcul(): double
IB
getValue()
Pour utiliser le couplage faible, nous devons utiliser les interfaces.
Considérons une classe A qui implémente une interface IA, et une classe B qui implémente une interface IB.
Si la classe A est liée à l’interface IB par une association, on dit que le classe A et la classe B sont liées par un
couplage faible.
Cela signifie que la classe B peut fonctionner avec n’importe quelle classe qui implémente l’interface IA.
En effet la classe B ne connait que l’interface IA. De ce fait n’importe quelle classe implémentant cette interface
peut être associée à la classe B, sans qu’il soit nécéssaire de modifier quoi que se soit dans la classe B.
Avec le couplage faible, nous pourrons créer des application fermée à la modification et ouvertes à l’extension.
AImpl
b:IB
Calcul(): double
BImpl
getValue() 12
13. Injection des dépendances
Injection par instanciation statique :
import metier.MetierImpl;
import dao.DaoImpl;
public class Presentation {
public static void main(String[] args) {
DaoImpl dao=new DaoImpl();
MetierImpl metier=new MetierImpl();
metier.setDao(dao);
System.out.println(metier.calcul());
}
}
13
14. Injection des dépendances
Injection par instanciation dynamique par réflexion :
• Fichier texte de configuration : config.txt
ext.DaoImp
metier.MetierImpl
import java.io.*;import java.lang.reflect.*;
import java.util.Scanner; import metier.IMetier;
import dao.IDao;
public class Presentation {
public static void main(String[] args) {
try {
Scanner scanner=new Scanner(new File("config.txt"));
String daoClassname=scanner.next();
String metierClassName=scanner.next();
Class cdao=Class.forName(daoClassname);
IDao dao= (IDao) cdao.newInstance();
Class cmetier=Class.forName(metierClassName);
IMetier metier=(IMetier) cmetier.newInstance();
Method meth=cmetier.getMethod("setDao",new Class[]{IDao.class});
meth.invoke(metier, new Object[]{dao});
System.out.println(metier.calcul());
} catch (Exception e) { e.printStackTrace(); }
}
}
14
15. Injection des dépendances avec Spring.
L'injection de dépendances est souvent la base de tout programme moderne.
L'idée en résumé est de déporter la responsabilité de la liaison des composants du programme dans
un framework afin de pouvoir facilement changer ces composants ou leur comportement.
Parmi les leaders du marché Java, il y a Spring IoC, Guice, Dagger ou encore le standard « Java EE »
CDI qui existe depuis Java EE 6.
Spring IOC commence par lire un fichier XML qui déclare quelles sont différentes classes à
instancier et d’assurer les dépendances entre les différentes instances.
Quand on a besoin d’intégrer une nouvelle implémentation à une application, il suffirait de la
déclarer dans le fichier xml de beans spring.
15
16. Injection des dépendances dans une application java standard
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd" >
<beans>
<bean id="d" class="dao.DaomImpl"></bean>
<bean id="metier" class="metier.MetierImpl">
<property name="dao" ref="d"></property>
</bean>
</beans>
D:DaoImpl
getValue()
Metie:MetieImpl
IDao dao
Calcul(): double 16
17. Injection des dépendances dans une application java standard
package pres;
import metier.IMetier;
import org.springframework.context.support.*;
public class Presentation {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-ioc.xml");
IMetier metier=(IMetier) context.getBean("metier");
System.out.println(metier.calcul());
}
}
17
18. • Annotations compatibles Java 5 et plus
• Objectifs
– Simplifier la configuration (convention over configuration)
– Limiter les fichiers de configuration XML
• Annotations dans Spring
– Annotations spécifiques à des couches d’architecture
• Présentation / Service / DAO (Data Access…)
Configuration par annotations
18
19. • Gestion des dépendances par annotations
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<bean id="..." class="..." />
</beans>
Balise pour « activer » les annotations
Inclusion du namespace context
Configuration XML pour l’injection
19
20. • Injection automatique des dépendances
• 2 annotations pour la même fonction
– @Autowired : annotation Spring
– @Inject : annotation JSR-330
• Spring supporte les 2 annotations
– @Autowired dispose d’une propriété (required) que n’a pas l’annotation @Inject. Ceci
est utile pour indiquer le caractère facultatif d’une injection.
• Résolution par type
– Se base sur le type de l'objet pour retrouver la dépendance à injecter.
@Autowired ou @Inject
20
22. @Autowired sur un mutateur
• Utilisation de @Autowired pour injecter helloWorld
import org.springframework.beans.factory.annotation.Autowired;
public class HelloWorldCaller {
private HelloWorld helloWorldService;
@Autowired
public void setHelloWorldService(HelloWorld helloWorldService){
this.helloWorldService=helloWorldService;
}
public void callHelloWorld(){
helloWorldService.sayHello();
}
}
22
23. • Injection à partir de l’identifiant du bean
• Nécessite Java 6 ou plus
• Se place devant un attribut ou un setter
• Par défaut, le nom est déduit du nom de la méthode (setter) ou de l’attribut
@Resource
package com.spring.formation;
import javax.annotation.Resource;
public class MovieManager {
@Resource(name="myMovieDAO")
private MovieDAO movieDAO;
public MovieManager() {}
public void setMovieDAO(MovieDAO movieDAO) {
this.movieDAO = movieDAO;
}
}
23
24. @Component : composant générique
@Service : Services métier
@Repository : accès aux données (DAO)
@Controller : contrôleur pour interface graphique (Web)
Stéréotype selon l’usage
24
25. • A utiliser conjointement à une annotation @Component ou dérivée
• Définit la portée d’un bean
– Par défaut (si non présent) : singleton
package com.spring.formation;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("monComposant")
@Scope("prototype")
public class MyComponent {
}
@Scope
25
27. Injection des dépendances dans une application web
Dans une application web, SpringIOC est appelé au démarrage du serveur en déclarant le listener
ContextLoaderListener dans le fichier web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Dans cette déclaration, ContextLoaderListener est appelé par Tomcat au moment du démarrage de l’application.
Ce listener cherchera le fichier de beans spring « spring-beans.xml » stocké dans le dossier WEB-INF. ce qui permet
de faire l’injection des dépendances entre MetierImpl et DaoImpl
27
28. Les composants de Spring
● Un Application Context (une des implémentations de l’interface
org.springframework.context.ApplicationContext) représente le conteneur Spring :
il est chargé de démarrer les beans, de les injecter, de les gérer, de les détruire
● Il en existe plusieurs sortes : WebApplicationContext pour les applications Web
par exemple
● Le rôle de cette classe est de prendre vos objets et votre configuration, et de
faire fonctionner l’ensemble
28
Objets métier
Configuration
Spring Application prête !
29. Création d’un contexte spécifique aux configurations d’annotations:
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MovieDAO mDAO = (MovieDAO) context.getBean("movieDAO");
}
Chargement du contexte
29
30. Encore plus facile en Spring Boot
@SpringBootApplication
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
// same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
30