Pour un Servlet normal, je suppose que vous pouvez déclarer un écouteur de contexte , mais pour Spring MVC Spring faciliterait-il la tâche?
De plus, si je définis un auditeur de contexte et que je devrais alors accéder aux beans définis dans mon servlet.xml
ou applicationContext.xml
, comment pourrais-je y avoir accès?
Spring a quelques événements standard que vous pouvez gérer.
Pour ce faire, vous devez créer et enregistrer un bean qui implémente l'interface ApplicationListener
, comme ceci:
package test.pack.age;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationListenerBean implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
}
Vous enregistrez ensuite ce haricot dans votre servlet.xml
ou applicationContext.xml
fichier:
<bean id="eventListenerBean" class="test.pack.age.ApplicationListenerBean" />
et Spring le notifiera lorsque le contexte de l'application sera initialisé.
Au printemps 3 (si vous utilisez cette version), la ApplicationListener
class est générique et vous pouvez déclarer le type d'événement qui vous intéresse et l'événement sera filtré en conséquence. Vous pouvez simplifier un peu votre code de bean comme ceci:
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
Depuis le printemps 4.2, vous pouvez utiliser @EventListener
_ ( documentation )
@Component
class MyClassWithEventListeners {
@EventListener({ContextRefreshedEvent.class})
void contextRefreshedEvent() {
System.out.println("a context refreshed event happened");
}
}
Créez votre annotation
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterSpringLoadComplete {
}
Créer une classe
public class PostProxyInvokerContextListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
ConfigurableListableBeanFactory factory;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
String[] names = context.getBeanDefinitionNames();
for (String name : names) {
try {
BeanDefinition definition = factory.getBeanDefinition(name);
String originalClassName = definition.getBeanClassName();
Class<?> originalClass = Class.forName(originalClassName);
Method[] methods = originalClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AfterSpringLoadComplete.class)){
Object bean = context.getBean(name);
Method currentMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
currentMethod.invoke(bean);
}
}
} catch (Exception ignored) {
}
}
}
}
Inscrivez cette classe par @Component Annotation ou en XML
<bean class="ua.adeptius.PostProxyInvokerContextListener"/>
et utilisez l'annotation où vous voulez sur n'importe quelle méthode que vous voulez exécuter après l'initialisation du contexte, comme:
@AfterSpringLoadComplete
public void init() {}
J'avais une seule application de page en entrant l'URL, il s'agissait de créer une HashMap (utilisée par ma page Web) contenant des données provenant de plusieurs bases de données. J'ai fait les choses suivantes pour tout charger pendant le démarrage du serveur.
1- Création de ContextListenerClass
public class MyAppContextListener implements ServletContextListener
@Autowired
private MyDataProviderBean myDataProviderBean;
public MyDataProviderBean getMyDataProviderBean() {
return MyDataProviderBean;
}
public void setMyDataProviderBean(MyDataProviderBean MyDataProviderBean) {
this.myDataProviderBean = MyDataProviderBean;
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("ServletContextListener destroyed");
}
@Override
public void contextInitialized(ServletContextEvent context) {
System.out.println("ServletContextListener started");
ServletContext sc = context.getServletContext();
WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(sc);
MyDataProviderBean MyDataProviderBean = (MyDataProviderBean)springContext.getBean("myDataProviderBean");
Map<String, Object> myDataMap = MyDataProviderBean.getDataMap();
sc.setAttribute("myMap", myDataMap);
}
2- Ajouté l'entrée ci-dessous dans web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.context.listener.MyAppContextListener</listener-class>
</listener>
3- Dans my Controller Class, code mis à jour pour vérifier d'abord la carte dans servletContext
@RequestMapping(value = "/index", method = RequestMethod.GET)
public String index(@ModelAttribute("model") ModelMap model) {
Map<String, Object> myDataMap = new HashMap<String, Object>();
if (context != null && context.getAttribute("myMap")!=null)
{
myDataMap=(Map<String, Object>)context.getAttribute("myMap");
}
else
{
myDataMap = myDataProviderBean.getDataMap();
}
for (String key : myDataMap.keySet())
{
model.addAttribute(key, myDataMap.get(key));
}
return "myWebPage";
}
Avec tous ces changements, lorsque je démarre Tomcat, il charge dataMap pendant startTime et met tout dans servletContext, qui est ensuite utilisé par Controller Class pour obtenir des résultats à partir de servletContext déjà rempli.
Veuillez suivre les étapes ci-dessous pour effectuer certains traitements après le chargement du contexte d'application, c'est-à-dire que l'application est prête à être utilisée.
Créer ci-dessous l'annotation i.e
@Retention (RetentionPolicy.RUNTIME) @Target (value = {ElementType.METHOD, ElementType.TYPE}) public @interface AfterApplicationReady {}
2.Create Below Class qui est un écouteur qui reçoit un appel lorsque l'état de l'application est prêt.
@Component
public class PostApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
public static final Logger LOGGER = LoggerFactory.getLogger(PostApplicationReadyListener.class);
public static final String MODULE = PostApplicationReadyListener.class.getSimpleName();
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
ApplicationContext context = event.getApplicationContext();
String[] beans = context.getBeanNamesForAnnotation(AfterAppStarted.class);
LOGGER.info("bean found with AfterAppStarted annotation are : {}", Arrays.toString(beans));
for (String beanName : beans) {
Object bean = context.getBean(beanName);
Class<?> targetClass = AopUtils.getTargetClass(bean);
Method[] methods = targetClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AfterAppStartedComplete.class)) {
LOGGER.info("Method:[{} of Bean:{}] found with AfterAppStartedComplete Annotation.", method.getName(), beanName);
Method currentMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
LOGGER.info("Going to invoke method:{} of bean:{}", method.getName(), beanName);
currentMethod.invoke(bean);
LOGGER.info("Invocation compeleted method:{} of bean:{}", method.getName(), beanName);
}
}
}
} catch (Exception e) {
LOGGER.warn("Exception occured : ", e);
}
}
}
Enfin, lorsque vous démarrez votre application Spring juste avant l’enregistrement de l’application de journal, votre auditeur sera appelé.