mercredi 10 avril 2013

First Steps with Spring



Introduction au framework Spring

                 Spring s'inscrit dans la liste des frameworks de développement des applications d'entreprise dans l'environnement J2EE. Il a été conçu en 2002 par Rod Johnson et actuellement, il est à sa version 3.2.
Il peut être définit comme étant un conteneur léger d'objets en java conçu dans le but de simplifier le développement des applications 3 tiers. Il est surtout vu comme étant léger par rapport au développement avec les EJB qui nécessitent obligatoirement un conteneur lourd d'EJB.

Il se base sur 3 domaines :

  •  L'inversion de contrôle IOC : Ce principe se pose sur l'injection de dépendances. Au lieu de laisser la responsabilité au programme de créer les objets, c'est le conteneur Spring qui s'en charge. "Don't call e, i'll call for you". Ce principe favorise le respect de certains patrons de conception tel que le couplage faible, le patron singleton et le patron abstract factory.

  • La programmation par aspect AOP : Cette méthode consiste à développer les modules techniques(les aspects) séparément du code métier et de les appeler lorsqu'on en a besoin. 

  •  Les couches d'abstractions : Spring offre un ensemble de templates qui permettent une intégration aisée certaines API telles que la template des Web Services, Hibernate ...

Un exemple pratique pour débuter avec Spring : 

            Pour cet article, on va commencer le développement avec Spring comme un débutant le fera.
Coté environnement technique, nous allons exploiter STS qui est un Eclipse intégrant tous les plugins nécessaires pour avoir la perspectives Spring et développer aisément avec Spring. Il est fournit sur le site officiel de Spring. Il peut être téléchargé à partir de ce lien : http://www.springsource.org/downloads/sts-ggts
Nous aurions pu utiliser un eclipse normal tel que Indigo ou Juno et lui intégrer le plugin Spring tool Suite.
Pour ajouter le plugin STS à eclipse il suffit de suivre les étapes suivantes :

Accèder au MarketPlace de Eclipse
Choisir le plugin associé à la version de Eclipse

Nous allons exploiter les puissantes fonctionnalités de Maven pour gérer les dépendances du projet.

Le développement sera en phases allant du plus évident au plus compliqué.
1- Nous allons en premier lieu créer un nouveau projet maven.
Pour ceux qui ne connaissent pas maven, il s'agit d'un outil open source pour la gestion de grands projets de développement. Il se base essentiellement sur un ensemble de phases qui sont détaillées dans l'image ci dessus :

Les phases d gestion d'un projet Maven

Cette dernière figure est extraite du site http://dcabasson.developpez.com/articles/java/maven/introduction-maven2/ qui donne un aperçu plus général sur la gestion de projet avec Maven.
Pour ajouter le plugin Maven dans eclipse, il suffit d'aller le chercher dans Eclipse "MarketPlace".
Intégration du plugin de Maven dans Eclipse

Pour notre cas, nous trouvons ce plugin aussi intégré dans le Spring Tool Suite.
Assurez vous que vous êtes sur la perspective Spring

La perspective Spring

Choississez file/new/others/Maven/Maven Project


  
                                           Création d'un projet Maven
Une fois le projet est crée, nous pouvons jeter un coup d'oeil rapide sur l'organisation des répertoires
La structure d'un projet Maven
2- Nous ajoutons la nature Spring au projet. Il suffit d'ajout la dépendance de Spring-context.
Pour cela, nous allons procéder comme suit :
On ouvre le fichier pom.xml et on passe à l'onglets "Dependencies". On fait un add et on tape "spring" :
Ici aucune dépendances n'est retrouvée. Cela est du au faite que le repository de Maven (l'emplacement de toutes les dépendances disponibles que ce soit localement ou à distance) n'est pas indéxé. Pour le faire, on fait Windows/show view/ other/Maven/Maven repositories.
La vue de Maven

Une fois la vue ci dessus est apparue, on fait bouton droit / Rebuild Index sur les deux repositories Local Repository et central.
Maintenant, on peut revenir  l'ajout de la dépendance de "spring-context".
La dépendance Spring-context
Dans la rubrique de <properties>, on procède à ajouter la version de Spring.
  <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
et on modifie la version de la dépendance : 
<version>${org.springframework.version}</version>
Le fichier pom.xml devient comme suit : 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.spring.example</groupId>
  <artifactId>MyFirstExample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>MyFirstExample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
      <version>${org.springframework.version}</version>    
    </dependency>
  </dependencies>
</project>

3- Maintenant, nous allons ajouter le dossier resources sous le répertoire : src/main et dans ce dossier, nous ajoutons le fichier de configuration de Spring en cliquant sur new/Spring Bean Configuration File.

Ajout de Spring Bean Configuration File
4 - Nous allons maintenant créer une simple classe POJO intitulée "Produit.java" afin de voire le mécanisme d'injection ds dépendances et la création des objets dédié au framework Spring.
On commence par créer le package com.spring.example.domain et dans ce dossier, nous allons créer la classe "Produit.java"
package com.spring.example.domain;

public class Produit {
    
    // Fields section
    private String code;
    private String libellé;
    private double prix_unitaire;

    // constructors section
    public Produit() {
    }

    public Produit(String code, String libellé, double prix_unitaire) {
        super();
        this.code = code;
        this.libellé = libellé;
        this.prix_unitaire = prix_unitaire;
    }

    // Getters_setters section
    public String getCode() {
        return code;
    }

    public String getLibellé() {
        return libellé;
    }

    public double getPrix_unitaire() {
        return prix_unitaire;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public void setLibellé(String libellé) {
        this.libellé = libellé;
    }

    public void setPrix_unitaire(double prix_unitaire) {
        this.prix_unitaire = prix_unitaire;
    }

    @Override
    public String toString() {
        return "Produit [code=" + code + ", libellé=" + libellé
                + ", prix_unitaire=" + prix_unitaire + "]";
    }
}



5- Maintenant, on passe  déclarer cette classe autant que bean dans le fichier de configuration de Spring. Autant que débutant, nous nous appuyons sur le fichier ApplicationContext.xml. Plus tard, nous allons découvrir comment on utilise les annotations pour ces déclarations. De ce fait, nous disons que Spring s'appuie sur deux manières de développement qui sont :
  • un développement par programmation.
  • un développement déclaratif.

Pour déclarer que la classe Produit est un bean Spring et pour l'instancier par le conteneur de Spring, nous ajoutons les lignes suivantes dans ApplicationContext.xml : 
<bean id="produit0" class="com.spring.example.domain.Produit"> 
<property name="code" value="P100"></property>
<property name="libellé" value="clé USB 16 go"></property>
<property name="prix_unitaire" value="15.500"></property>
</bean>

6- La dernière étape pour ce simple projet Spring est d'écrire le code client qui permet d'initialiser le contexte Spring et d'appeler le bean.

package com.spring.example.client;



import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.example.domain.Produit;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        //Démarrer le conteneur spring(Bootstrup it)
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        
        
        //Accèder aux objets du conteneur
        Produit produit = context.getBean("produit0", Produit.class);
        System.out.println(" Bean produit : "+produit);
        
        System.out.println( "FIN DE PROGRAMME ...." );
    }
}
7- Pour exécuter ce projet, on lance en premier lieu la commande maven compile ensuite la commande package. On fait un clique droit sur la racine du projet/runAs/maven build
et on saisit la tâche "compile" à excécuter.
Maven compile
Et de la même façon, on génére le jar de l'application avec "package".
Maven package

8- Maintenant, on fait un "Run as" et le résultat est le suivant : 
Console d'appel d'un bean Spring
On arrive à la fin de ce premier exemple d'utilisation de framework Sping. Nous avons détaillé les étapes élémentaires et les plus évidentes pour développer une application qui exploite le framework Spring.

Des réflexions sur le mécanisme d'injection des dépendances: 

Pour ce qui procède, nous avons déclarer une simple classe POJO et nous avons injecté une instance du produit dans la classe client. Si on regarde la déclaration du bean Produit dans le fichier ApplicationContext.xml, nous avons utilisé le mécanisme d'injection par les méthodes setters.
Cependant, Spring définit trois méthodes d'injection de dépendances : 
  •  Injection par les méthodes setters : 
<bean id="produit0" class="com.spring.example.domain.Produit"> 
<property name="code" value="P100"></property>
<property name="libellé" value="clé USB 16 go"></property>
<property name="prix_unitaire" value="15.500"></property>
</bean>
  • Injection par le constructeurs :
<!--  CONSTRUCTOR INJECTION-->
<bean id="produit1" class="com.spring.example.domain.Produit"> 
<constructor-arg name="code" value="P200"></constructor-arg>
<constructor-arg name="libellé" value="Souris optique "></constructor-arg>
<constructor-arg name="prix_unitaire" value="15.200"></constructor-arg>
</bean>
  • Injection par une méthode d'initialisation :
<bean id="produit2" class="com.spring.example.domain.Produit" init-method="initializeIT"> 
</bean>
et on ajoute dans la classe Produit.java la méthode "initializeIT()"
 //Methods section
    public void initializeIT()
    {code="P300";
    libellé="TOTO";
    prix_unitaire=200.300;
    }

Injection des collections de type Map:

9- Maintenant, nous allons complexer un peu la situations. Nous allons dire qu'une commande contient une liste de produits.
Pour le faire, nous allons créer une nouvelle classe intitulée "Commande.java" dans le package "com.spring.example.domain".
package com.spring.example.domain;

import java.util.Map;

public class Commande {
    // Fields section
    private String code_commande;
    private Map<String, Produit> produit;

    // Constructor section
    public Commande() {
        // TODO Auto-generated constructor stub
    }

    public Commande(String code_commande, Map<String, Produit> produit) {
        super();
        this.code_commande = code_commande;
        this.produit = produit;
    }

    // Getters-setters Section
    public String getCode_commande() {
        return code_commande;
    }

    public void setCode_commande(String code_commande) {
        this.code_commande = code_commande;
    }

    public Map<String, Produit> getProduit() {
        return produit;
    }

    public void setProduit(Map<String, Produit> produit) {
        this.produit = produit;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Produit p : produit.values())
            sb.append(p.toString());
        return "Commande [code_commande=" + code_commande + ", produit="
                + sb.toString() + "]";
    }

}
10- Nous déclarons cette classe autant que bean Spring dans le ficher ApplicationContext.xml.


<bean id="commande0" class="com.spring.example.domain.Commande">
<property name="code_commande" value="C100"></property>

        <property name="produit">
            <map>
                <entry key="P100" value-ref="produit0"></entry>
                <entry key="P200" value-ref="produit1"></entry>
                <entry key="P800" value-ref="produit2"></entry> 

            </map>

        </property>
    </bean>

11- Nous ajoutons l'appel au bean "commande" dans la classe "client" :

 Commande commande = context.getBean("commande0", Commande.class);
        System.out.println(commande);


ApplicationContext Vs BeanFactories:

Dans cet exemple, nous avons utilisé un contexte d'application alors que nous aurions pu utiliser seulement une factory de création de bean.
Le rôle de la "beanfactory" est de créer les instances des objets et de les injecter dans les beans qui en dépendent. Cependant, "applicationContext" offre plus de services de framework tel que l'aop, les transactions, ....

Le code source de cet exemple :

 Le code source de cet exemple est téléchargeable à partir du lien :

Spring AOP