webflow tutorial mvc modelo modelandview formulario español ejemplo spring model-view-controller applicationcontext

spring - tutorial - ¿Cómo agregar un gancho al evento de inicialización del contexto de la aplicación?



spring webflow tutorial (5)

Crea tu anotación

@Retention(RetentionPolicy.RUNTIME) public @interface AfterSpringLoadComplete { }

Crear clase

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) { } } } }

Registre esta clase mediante la anotación @Component o en xml

<bean class="ua.adeptius.PostProxyInvokerContextListener"/>

y use la anotación donde desee utilizar cualquier método que desee ejecutar después de inicializado el contexto, como:

@AfterSpringLoadComplete public void init() {}

Para un Servlet normal, supongo que podrías declarar un oyente de contexto , pero para Spring MVC, ¿Spring lo haría más fácil?

Además, si definiera un oyente de contexto y luego tuviera que acceder a los beans definidos en mi servlet.xml o applicationContext.xml , ¿cómo podría obtener acceso a ellos?


Desde Spring 4.2 puedes usar @EventListener ( documentation )

@Component class MyClassWithEventListeners { @EventListener({ContextRefreshedEvent.class}) void contextRefreshedEvent() { System.out.println("a context refreshed event happened"); } }


Siga el paso siguiente para realizar un procesamiento después de que el Contexto de la aplicación se cargue, es decir, la aplicación está lista para servir.

  1. Crear una anotación a continuación, es decir,

    @Retention (RetentionPolicy.RUNTIME) @Target (value = {ElementType.METHOD, ElementType.TYPE}) public @interface AfterApplicationReady {}

2. Crear debajo de la clase que es un oyente que obtiene una llamada en el estado listo para la aplicación.

@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); } } }

Finalmente, cuando inicie su aplicación Spring justo antes de que inicie el registro, la aplicación se iniciará y se llamará a su oyente.


Tenía una aplicación de una sola página al ingresar la URL que estaba creando un HashMap (usado por mi página web) que contenía datos de múltiples bases de datos. Hice cosas para cargar todo durante la hora de inicio del servidor-

1- Creado 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- Agregado debajo de la entrada en web.xml

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.context.listener.MyAppContextListener</listener-class> </listener>

3- En mi clase Controlador código actualizado para verificar primero el Mapa en 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"; }

Con este gran cambio cuando inicio mi tomcat, carga dataMap durante startTime y pone todo en servletContext que luego usa Controller Class para obtener resultados de servletContext ya poblado.


Spring tiene algunos eventos estándar que puedes manejar.

Para hacerlo, debe crear y registrar un bean que implemente la interfaz ApplicationListener , algo como esto:

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

Luego registra este bean dentro de su archivo servlet.xml o applicationContext.xml :

<bean id="eventListenerBean" class="test.pack.age.ApplicationListenerBean" />

y Spring lo notificará cuando se inicialice el contexto de la aplicación.

En Spring 3 (si está utilizando esta versión), la clase ApplicationListener es genérica y puede declarar el tipo de evento que le interesa y el evento se filtrará en consecuencia. Puedes simplificar un poco tu código de bean así:

public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); // now you can do applicationContext.getBean(...) // ... } }