Hello World Spring
Le framework Spring implémente le design pattern IoC (inversion de contrôle). Le petit exemple qui va suivre a pour but de donner un petit exemple simple d'utilisation de cette API.
Tout d'abord on souhaite réaliser une application qui affiche "Hello World". On souhaite que cette application soit le plus paramétrable possible. En fait elle doit permettre d'afficher "Hello World" sur une sortie quelconque.
Il s'agit donc de rendre la sortie générique.
La première implémentation se ferait à l'aide de deux classes :
Pour commencer, la classe application
package net.olivier_thebault;
import net.olivier_thebault.screen.Screen;
public class HelloWorld {
public Screen scr=new Screen();
public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld();
helloWorld.scr.show("Hello world !!!");
}
}
puis une classe d'affichage :
package net.olivier_thebault.screen;
public class Screen {
public void show(String text){
System.out.println(text);
}
}
Dans cet exemple, la classe application ne connait pas la méthode d'affichage, elle sait juste qu'il existe une classe Screen. Le problème est si l'on souhaite modifier la sortie, on doit créer une nouvelle classe d'affichage, NewScreen par exemple et modifier le programme principal en conséquence. Dans un cas simple, comme celui-ci, cela n'est pas très difficile, mais imaginons simplement, que l'on est plusieurs instances de Screen, donc plusieurs appels à new Screen(), la modification du programme serait alors beaucoup plus longue et accidentogène.
En plus ce ça il faudrait recompiler l'application.
Je vais alors faire une petite modification pour mieux séparer l'affichage du programme : rajouter une interface. En fait il s'agit d'établir un contrat entre la classe principale et la classe d'affichage. Cela aura pour avantage d'externaliser la liaison entre les deux classes
On obtient alors ceci pour l'interface :
package net.olivier_thebault;
public interface IScreen {
public abstract void show(String text);
}
et ceci pour les deux autres classes :
package net.olivier_thebault;
import net.olivier_thebault.screen.Screen;
public class HelloWorld {
public IScreen scr=new Screen();
public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld();
helloWorld.scr.show("Hello world !!!");
}
}
package net.olivier_thebault.screen;
import net.olivier_thebault.IScreen;
public class Screen implements IScreen {
/* (non-Javadoc)
* @see net.olivier_thebault.screen.IScreen#show(java.lang.String)
*/
public void show(String text){
System.out.println(text);
}
}
Cela va nous permettre d'externaliser complétement la référence à la classe Screen, en introduisant une nouvelle classe. Pour commencer le champ "scr" va être initialisé par le constructeur
package net.olivier_thebault;
public class HelloWorld {
public IScreen scr;
public void hello(){
scr.show("Hello world !!!");
}
public HelloWorld(IScreen scr){
this.scr = scr;
}
}
De fait il n'existe plus aucune référence au constructeur et à la classe Screen. De plus cette classe ne sera plus la classe principale du programme, elle perd sa méthode main au profit d'une méthode Hello
La classe principale sera désormais :
package net.olivier_thebault;
import net.olivier_thebault.screen.Screen;
public class HelloMain {
public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld(new Screen());
helloWorld.hello();
}
}
D'accord, tout ce qui est fait pour le moment est de déplacer le problème vers une nouvelle classe, ce qui a tendance à complexifier la solution, qui en plus est partielle. Il est donc temps d'améliorer et simplifier tout ça. C'est à que Spring peut rendre les choses plus confortable. Pour commencer il faut créer un fichier de configuration dont le rôle est de préciser quel est l'instance à passer à HelloWorld au moment de sa construction.
<?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-2.5.xsd">
<bean id="Hello" class="net.olivier_thebault.HelloWorld">
<constructor-arg>
<bean class="net.olivier_thebault.screen.Screen" />
</constructor-arg>
</bean>
</beans>
L'important ici se situe dans la balise bean. Id précise le nom que spring va donner à la classe. Ce nom va servir ensuite au moment de l'appel au constructeur. On précise ensuite, grace à la balise "constructor-arg" la classe implémentant l'interface IScreen. Spring va automatiquement créer l'instance qui va bien. C'est ici que l'on trouve le seul lien entre l'application et la classe d'affichage. Ce qui veut dire que l'on peut modifier l'application uniquement par paramétrage sans recompiler.
Le programme principal devient alors ceci :
package net.olivier_thebault;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
public class HelloSpring {
public static void main(String[] args) {
// on récupère le fichier de configuration
Resource is = new FileSystemResource("config.xml");
// à partir du fichier de config on récupère une factory qui va permettre de construire
// les beans.
BeanFactory factory = new XmlBeanFactory(is);
// Le constructeur passe par spring
HelloWorld hello=(HelloWorld)factory.getBean("Hello");
hello.hello();
}
}
Voici donc un petit exemple d'Ioc via Spring. Spring permet de faire beaucoup plus de choses, de gérer les singletons, les transactions ou de créer des applications selon le modèle MVC. Il peut aussi s'interfacer avec struts ou hibernate.
