Cet article a pour but de parcourir les étapes de création et de publication d’une application JEE dans la forge PAAS CloudFoundry. Celle-ci, supportée par VMWare, profite largement des nouveautés de Spring 3.1 (à ce jour encore en RC2).

La particularité est qu’elle se décline en une version portable (ou installable dans son infrastructure privée) au travers de sa version MicroCloudFoundry.

Pourquoi aller dans le Cloud ?

Les motivations peuvent être variées ; c’est sous l’axe suivant que nous avons mis en place nos applications dans la CloudFoundry :

  • La mise en ligne d’applications facilitée avec l’accès à des environnements en tant que services,
  • La simplification des démarches d’administrations afférentes,
  • La montée en charge, avec un ajout d’instances à la volée et une réserve de puissance illimitée … ou disons plutôt très importante.

… Mais tout d’abord, un petit tour de la forge de VM Ware :

Avec CloudFoundry, nous avons la possibilité de déclarer des services à partir d’un portefeuille déjà bien garni de briques techniques pour structurer notre socle applicatif adapté au cloud:

  • MySQL & PostgreSQL, pour les bases relationnelles,
  • RabbitMQ, un bus de message qui orchestrera les services et une part de la répartition de la charge,
  • MongoDB et Redis, des bases clé/valeurs très souples d’utilisation et très performantes.

Les applications sont packagées sous la forme de war et déployées par console sur un tomcat adapté à la sauce VMWare.

Remarque : celles-ci sont appelées à s’étoffer avec la version open-source sur cloudfoundry.org.

Se projeter vers une solution cloud, c’est se conformer à certains paradigmes techniques liés à la ‘dématérialisation’ des applicatifs : nous ne sommes pas figés sur un serveur physique ou une localisation arrêtée des données.
Ceci n’est pas sans conséquences sur la façon dont l’architecture de l’application est établie, ni sur le processus de publication. Par exemple :

  • Les ressources statiques ne sont pas enregistrées dans le système de fichier, mais sur sur une base clé / valeur,
  • Les sessions doivent gérées en fonction du load balancing,
  • Les transactions ne sont pas aussi nettement définie que sur une application classique, et on procède par solution approchante (exemple : http://www.mongodb.org/display/DOCS/Atomic+Operations)

Nous allons donner un aperçu des étapes de mise en place d’une application en utilisant les possibilités offertes par Spring pour orchestrer le tout.
La constellation Spring (Core, Data, Integration, Web-Services,…) est supportée par VM Ware qui en a fait son socle technique pour structurer les applications éligibles à son cloud, ce qui en fait une approche naturelle pour concevoir notre application.

Configuration du fichier de contexte Spring

Notre fichier applicationContext.xml est la pierre angulaire de notre configuration, et se distingue par :

  • 1- Les espaces de noms utilisés :
    1
    2
    3
    4
    5
    6
    7
    8
    
    	<beans xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:cache="http://www.springframework.org/schema/cache"
    	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    	xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:cloud="http://schema.cloudfoundry.org/spring"
    	xmlns:mongo="http://www.springframework.org/schema/data/mongo"

    Ils représentent la multiplicité des technologies en jeu dans notre architecture: du jdbc (pour MySQL), du data (pour Mongo), du cache (nouveauté 3.1 apportant une abstraction de solutions de cache)…

  • 2- L’utilisation de profiles et des balises ‘cloud’ qui facilite le raccrochement aux services déclaré dans notre espace cloud
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    <beans profile="default">
    	<bean id="mongoDbFactory"  class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
    			<constructor-arg name="mongo">
    				<mongo:mongo  host="127.0.0.1"/>
    			</constructor-arg>
    			<constructor-arg name="databaseName" value="mongoimages"/>
    		</bean>
    		<bean class="org.apache.commons.dbcp.BasicDataSource" 			destroy-method="close" id="dataSource"><property name="testOnBorrow" value="true" />
    		</bean>
    </beans>
     
    <beans profile="cloud">
    		<cloud:mongo-db-factory id="mongoDbFactory"  service-name="mongoimages" />
    		<cloud:data-source id="dataSource" service-name="masqlbase"/>
    </beans>

    Les dépendances maven correspondantes sont, entre autres :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    <properties><org.cloudfoundry-version>0.8.1</org.cloudfoundry-version>
    		<org.cloudfoundry-group>org.cloudfoundry</org.cloudfoundry-group>
    		<org.spring-data-mongo-version>1.0.0.M4</org.spring-data-mongo-version>
    		<spring.version>3.1.0.RC2</spring.version>
    	</properties>
    	<dependencies>
     
    		<dependency>
      			<groupId>org.cloudfoundry</groupId>
      			<artifactId>cloudfoundry-runtime</artifactId>
      			<version>${org.cloudfoundry-version}</version>
    		</dependency>
     
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-core</artifactId>
    			…
     
    		<dependency>
    			<groupId>org.springframework.data</groupId>
    			<artifactId>spring-data-mongodb</artifactId>
    			<version>${org.spring-data-mongo-version}</version>
    		</dependency>

Les bonnes pratiques de développement avec Spring pour le cloud:

  • 1) Séparer la définition de ses beans pour séparer le local du mode production

    On initialise un profile avec la découverte automatique de l’environnement :
    using-bean-profiles-on-cloud-foundry

  • 2) Utilisation des balises ‘cloud’
    Elles rattachent le service correspondant sous le nom de bean réservé, en toute transparence. Par exemple :

    1
    2
    3
    
    <beans profile="cloud">
    		<cloud:mongo-db-factory id="mongoDbFactory"  service-name="acimage" />
    		<cloud:data-source id="dataSource" service-name="acibase2"/>
  • 3) Utilisation de Spring-Data pour la persistance avec MongoDB
    Les objets MongoTemplate injectés par Spring offrent des facilités de requêtage et de transtypage des résultats.

    1
    2
    3
    4
    5
    6
    7
    8
    
    @Autowired
    MongoTemplate template;
     
    @Override
    public byte[] getImage(String nom) {
    	try {
    		final Acimage findOne = template.findOne(query(where("nom").is(nom)), Acimage.class,AppMongoConfig.MONGO_NOM_COLLECTION_IMAGE);
    ...
  • 4) Cacher les données peu volatiles avec Spring 3.1
    On définit des régions pour le cache de données pour y stocker les résultats de requêtes fréquentes et peu changeantes ; puis on attache aux méthodes susceptibles de changer les données les événements de nettoyage du cache.
    On sollicite d’autant moins les sources de données sous-jacentes.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    @Cacheable(value=MonAppCacheRegion.SUPER_CATEGORIE_REGION)
    	public List<SuperCategorie> toutesSuperCategoriesActives() {
    		final TypedQuery<SuperCategorie> requete = entityManager.createQuery(" select c from SuperCategorie c where c.etat = :status",SuperCategorie.class);
    		requete.setParameter("status", 'A');
    		return requete.getResultList();
    	}
     
    	@Cacheable(value=MonAppCacheRegion.CATEGORIE_ID)
    	public Categorie categorieParId(Integer id) {
    		return entityManager.find(Categorie.class, id);
    	}
     
    	@Override
    	@CacheEvict(value={MonAppCacheRegion.CATEGORIE_PAR_SUPER,MonAppCacheRegion.CATEGORIE_REGION,MonAppCacheRegion.SUPER_CATEGORIE_REGION,MonAppCacheRegion.CATEGORIE_ID},allEntries=true)
    	public Categorie merge(Categorie detachedInstance) {
    		return super.merge(detachedInstance);
    	}
  • 5) L’utilisation de Spring Tools Suite (>= 2.8) pour piloter les applications et leur déploiement.
  • Console CloudFoundry dans Spring Tools Suite

    Console CloudFoundry dans Spring Tools Suite

    Par ailleurs, CloudFoundry offre:

    • Un monitoring en cours d’ouverture au public (dans l’esprit de Spring Insight )
      Suivi des performances dans Cloud foundry

      Suivi des performances dans Cloud foundry

    • Un échange de données bi-directionnel entre le Cloud et l’entreprise au travers de Tunnels.
    • Une multiplicité de langages supportés au-delà de Java & Groovy : Scala, Ruby …

    Comme nous l’avons vu, les adhérences ne sont pas trop coercitives et la souplesse offerte par Spring se révèle très agréable quand il s’agit de jongler entre un environnement de développement partiellement représentatif du cloud et un environnement de production.
    Certains points, comme la mise en place de SSL restent un peu plus subtiles à mettre en place (Setup-SSL-on-cloudfoundry-landscape), ou en cours de construction (comme la cohabitation de la gestion des sessions et de répartition de la charge).

    , , ,