Spring PostProcessor

BeanPostProcessor

Chaque BeanPostProcessor est appelé durant la phase de création d’un bean (avant et aprés la méthode d’initialisation d’un bean).
Tous les BeanPostProcessor seront appelés pour chaque instance de bean créée.

@Component //(@Named - JSR 330)
public class InformationBeanPostProcessor implements BeanPostProcessor {
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("\n '" + beanName + "' est de type : " + bean.getClass().getCanonicalName() + "\n");
      return bean;
   }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      return bean;
   }
}

Par exemple, le BeanPostProcessor ci-dessus permet d’indiquer le “nom” et le “type” de chaque bean de l’ApplicationContext.

Pour ne traiter que certains bean, il faut filtrer sur le type du bean :

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   if(bean instanceOf ....){
      //traitement
    }
 return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if(bean instanceOf ....){
      //traitement
    }
 return bean;
}

ATTENTION A BIEN TOUJOURS RETOURNER LE BEAN !!

BeanFactoryPostProcessor

Traite les meta-data des beans et non les instances de bean (comme le BeanPostProcessor).

Spring AOP

spring AOP

Aspect = Join Point + Advice

Advice : le code à exécuter
Join Point : l’endroit où va être injecté ce code à exécuter

Un Join Point est définit par le Poincut : une expression (ou une annotation) permettant d’identifier/définir les Joint Points.

Type d’aspets

5 types d’advices sont possibles:

  • Before advice : s’exécute avant le Join point. S’il lance une Exception, le Join point ne sera pas appelé
  • After returning advice : s’exécute après le Join point, si celui-ci s’est bien exécuté (s’il n’y a pas eu d’Exception)
  • After throwing advice : s’exécute si une Exception a été lancée pendant l’exécution du Join point
  • After advice : s’exécute après le Join point, qu’il y ait eu une Exception ou non
  • Around advice : s’exécute autour du Join point.

Tous ces advices sont dérivés de l’interface org.aopalliance.aop.Advice (parent notament de l’interface MethodInterceptor -_Around advice_- utilisée dans la gestion des transactions de Spring).

Spring ne supporte que les joint points à l’exécution des méthodes (car l’AOP de Spring est basé sur des proxies et non du weaving comme avec AspectJ).

Références

Configuration de Spring

L’ensemble de la configuration de Spring est accessible via l’API Environment qui permet de manipuler les profiles et les properties.

Acceder à l’environment:

@Component
public class Application {

   @Inject
   ConfigurableEnvironment environment;

}

Todo : vérifier si dans le lifeCycle, ContextAware, etc.. il n’y a pas acces à cet environement

Spring JPA

Avec JPA, la gestion des entités est assurée par un EntityManager. Les méthodes fournies par l’EntityManager (API) permettent au code applicatif d’effectuer les opérations propres à la persistance.

Les instances d’EntityManager sont fournies par une factory : l’EntityManagerFactory.
Avec Spring, cette EntityManagerFactory sera construte et injectée dans l’application par une FactoryBean : l’EntityManagerFactoryBean.

##EntityManagerFactoryBean

Spring JPA EntityManagerFactory

L’EntityManagerFactoryBean va instancier une EntityManagerFactory en se basant sur les inner beans de type DataSource et JpaVendorAdapter. Cette EntityManagerFactory sera chargée de fournir à l’application les EntityManager dont elle à besoin.

Spring propose 3 types d’EntityManagerFactoryBean :

  • :-1: LocalEntityManagerFactoryBean : sans grand intéret
  • :ok_hand: Obtaining an EntityManagerFactory from JNDI : si on utilise le serveur JEE comme conteneur JPA.
  • :+1: LocalContainerEntityManagerFactoryBean : si on utilise Spring comme conteneur JPA. C’est souvent la méthode utilisée mais attention à l’interference avec un serveur JEE si le fichier persistence.xml se trouve à l’emplacement réglementaire /META-INF/persistence.xml.

On remarque que la gestion des transactions ne fait pas partie de SPRING JPA.
C’est normal car la gestion des transactions recouvre un domaine plus vaste que JPA seul.

(Voir Spring et les transactions)

DataSource

Une DataSource est une interface définie par la norme JDBC, qui permet d’encapsuler la création et la gestion des Connections physiques au(x) SGBD, afin d’isoler le code client de toutes cette plomberie de bas niveaux.
On a donc un code client extremement simplifié, du genre :

DataSource ds = [récupération d'une référence vers la datasource]
Connection con = ds.getDataSource();

Avec Spring, la récupération de la référence vers la datasource dans le code applicatif est effectuée par l’injection de dépendances du conteneur, ce code n’existe donc pas explicitement.

Création des Connections

Les connections sont les liens directs avec les SGBD JEE Datasource : creation des connection AOP Pour les créer il faut donc connaitre:

  • Le driver JDBC (par exemple org.hsqldb.jdbcDriver)
  • L’URL du SGBD (jdbc:hsqldb:file:jpa-by-examples/database//jpa.db)
  • le login de l’utilisateur
  • le mot de passe de l’utilisateur

Gestion des Connections

Les connections sont généralement gérées au sein d’un pool par des datasource étendant l’interface ConnectionPoolDataSource. JEE Datasource : creation des connection AOP

Il faudra donc fournir des information sur le dimensionnement du pool de connection et le comportement du pool.

Par exemple, pour le pool fournit par Tomcat:

Dimensionnement Comportement
maxActive
maxIdle
minIdle
initialSize
maxWait
defaultTransactionIsolation

….

JpaVendorAdapter

TODO

Spring et les transactions

Pour gérer les transaction, Spring va utiliser un gestionnaire de transaction (Transaction Manager).
Pourquoi ? parce que la manipulation des transaction directement en Java est complexe et hétérogène au niveau des API.

Transaction & Java

Transaction JDBC

Par défaut en JDBC, chaque appel à la base de données correspond à une transaction compléte, c’est l’auto-commit.:

ouverture Tx –> Exécution de l’opération –> fermeture Tx.

En JDBC la gestion des transaction s’effectue :

  • en désactivant le mode auto-commit Connection.setAutoCommit(false).
  • en appelant explicitement Connection.commit() ou Connection.rollback() pour fermer la transaction.

voir ce blog pour plus de détail.

Transaction JTA

Avec JDBC, on l’a vu, la gestion des transactions est indissociable de la connection au SGBD. On gère les transactions directement au niveau de l’objet Connection.
JTA (Java Transaction API) permet de découpler la gestion des transaction de la connection (“physique”) sous-jacente.
En effectuant cette abstraction, il devient possible de gérer plusieurs connections différentes au sein de la même transaction (plusieurs SGBD, mix JDBC et JMS, …).

Ce type d’API n’est pas necessaire dans la plupart des cas (accés au même back-end durant la transaction) et les implémentations ne sont disponibles de base que dans les Serveur JEE complet (Websphere, JBoss, …) mais pas dans Tomcat par exemple.

Transaction fournit par les ORM

Les ORM fournissent géneralement une API spécifique afin de gérer les transaction.
Par exemple Hibernate fourni ces propres interfaces Session et Transaction pour cette gestion :

Session sess = factory.openSession();
 Transaction tx;
 try {
    tx = sess.beginTransaction();
    //do some work
     ...
     tx.commit();
  }
  catch (Exception e) {
     ...
  }

L’approche Spring : PlatformTransactionManager

Afin d’uniformiser toutes ces API de gestion des transactions, Spring fourni une API uniformisée PlatformTransactionManager.
Les différentes implémentations fournies par Spring, appelées gestionnaire de transactions, permettront de traiter n’importe quelle démarcation transactionnelle de manière identique.

Comme pour la datasource, le gestionnaire de transaction sera injecté par Spring.
Mieux encore, le gestionnaire de transaction sera invoqué/piloté par un Aspet (TransactionInterceptor) dont les join points seront définis par l’annotation @Transactional
=> pas de code applicatif mais juste de la configuration. :smile:

Pour que la prise en compte des join points @Transactional soit effective, il faut ajouter :

  • @EnableTransactionManagement à une classe de configuration (@Config).
  • <tx:annotation-driven/> dans le fichier de configuration XML.


Published

28 October 2014

Tags