Détails :
Dans les 2 premiers tutoriels Superviser une application java avec Spring et JMX (1) et (2), nous avons exposé avec Spring un MBean permettant de ré-initialiser un service de configuration sans redémarrer le serveur.
Nous avons aussi la méthode de ré-initialisation via la console JConsole fournie avec la JDK.
Le but de ce tutoriel est de mettre en place une solution permettant d'accéder au MBean exposé, sans allé dans la JConsole, mais plutôt en passant par une autre application web backoffice.


(Les sources du projet sont disponibles en annexe)

Précisions :
Pour ce tutoriel, le projet initial a été découpé en 3 projets et un nouveau projet a été créé :

  • mp-spring-jmx-parent : projet "pom", permet de gérer les dépendances et les modules avec maven. Contient les modules suivant :
  • mp-spring-jmx-common : projet "jar", contient les classes communes utilisées par l'application web principale et le backoffice
  • mp-spring-jmx-webapp : projet "war", application web principale équivalente au projet mp-spring-jmx-2, sans les classes communes déportées dans mp-spring-jmx-common
  • mp-spring-jmx-backoffice : projet "war", application web backoffice. utilise aussi mp-spring-jmx-common

Dans cet exemple, les 2 applications web sont déployés en local, sur le même serveur tomcat. Mais il est tout à fait possible de les déployer sur des machines différentes...

1- Le pourquoi du projet commun mp-spring-jmx-common
Au final nous voulons avoir une application web principale "pilotée" par une autre application web backoffice. Dans cette exemple nous voulons juste ré-initialiser un service de l'application principale. Donc appeler une méthode avec ou non des arguments.
Par conséquent nous allons créer un "contrat" entre les deux applications. Qui dit contrat, dit Interface.
Ainsi, nous déplaçons l'interface ConfigurationServiceMBean dans le projet mp-spring-jmx-common, et uniquement l'interface. Le backoffice n'a pas besoins de savoir comment est implémentée la méthode void reInitConfigurationService(). Il doit juste savoir que cette méthode existe.

2- Backoffice : création d'un service pour gérer la ou les webapp
Pour gérer une ou plusieurs webapp, nous créons le service suivant dans le backoffice :

public interface WebappManagementService {
 
	/**
	 * Méthode permettant de ré-initialiser le service de 
	 * configuration de la principale application web.
	 */
	void reInitPrincipalWebappConfigurationService();
}

avec son implémentation...

public class WebappManagementServiceImpl implements WebappManagementService {
 
	private ConfigurationServiceMBean configurationServiceMBean;
 
	private static Log logger = LogFactory.getLog(WebappManagementServiceImpl.class);
 
	public void reInitPrincipalWebappConfigurationService() {
		logger.info("Re-initialisation du service de configuration (principal webapp)");
		configurationServiceMBean.reInitConfigurationService();
	}
 
	public void setConfigurationServiceMBean(
			ConfigurationServiceMBean configurationServiceMBean) {
		this.configurationServiceMBean = configurationServiceMBean;
	}
}


3- Backoffice : injection et classe proxy...
A aucun moment nous n'avons écrit une méthode qui permet de récupérer un MBean exposé sur un serveur. Et pourtant nous faisons bien appel à la méthode reInitConfigurationService() dans la classe WebappManagementServiceImpl. Pour que le tout fonctionne nous allons configurer le fichier applicationContext.xml du backoffice afin que Spring puisse :

  • créer une instance d'un objet proxy implémentant l'interface ConfigurationServiceMBean
  • injecter cette instance dans notre service WebappManagementService

Tout d'abord nous définissons de manière classique le service WebappManagementService :

<!-- Service de management des webapp -->
<bean id="webappManagementService" 
	class="fr.minimarmotte.projects.service.impl.WebappManagementServiceImpl">
	<property name="configurationServiceMBean" ref="proxy"/>
</bean>

Puis nous créons le proxy :

<!-- Recupération d'une instance d'un objet proxy permettant de re-router les appels au MBean nommé 
	"configurationServiceMBean2" -->
<!-- Rappel : ce MBean a été exposé par l'application web mp-spring-jmx-webapp -->
<bean id="proxy"
	class="org.springframework.jmx.access.MBeanProxyFactoryBean">
	<property name="objectName" value="bean:name=configurationServiceMBean2" />
	<property name="proxyInterface"
		value="fr.minimarmotte.projects.mbean.ConfigurationServiceMBean" />
</bean>

On passe en paramètre le nom du MBean avec lequel on veut communiquer : <property name="objectName" value="bean:name=configurationServiceMBean2" />
Et on indique à partir de quelle interface créer le proxy (interface commune aux 2 applications web...)

Cette configuration fonctionne en local, lorsque les 2 applications sont déployées sur le même Tomcat. Pour agir sur des serveurs à distance, voir Spring 2.5 reference chapter 20.6. Accessing MBeans via Proxies.

4- Backoffice : test dans une servlet...
Pour tester que l'on peut ré-initialiser le service de configuration de la webapp principale à partir du backoffice, on crée une servlet AdministrerWebappAction, dont voici un bout de code :

WebappManagementService webappManagementService = ServiceLocatorBackoffice.getWebappManagementService();
webappManagementService.reInitPrincipalWebappConfigurationService();

Il est alors possible de refaire le test en changeant une clé dans le fichier .properties, puis en appelant http://127.0.0.1:8080/mp-spring-jmx-backoffice/administrer_webapp .