web-dev-qa-db-fra.com

Comment ajouter un hook à l'événement d'initialisation du contexte de l'application?

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?

62
teddy teddy

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(...)
        // ...
    }
}
96
Bogdan

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");
    }
}
81
dgtc

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() {}
6
Adeptius

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.

1
Amit Singh

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.

  1. 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é.

0
Dilip Dumania