Spring Supporting tagline
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
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
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 :
-
LocalEntityManagerFactoryBean : sans grand intéret
-
Obtaining an EntityManagerFactory from JNDI : si on utilise le serveur JEE comme conteneur JPA.
-
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
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.
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()
ouConnection.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.
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.