如何将钩子添加到应用程序上下文初始化事件?
对于一个常规的Servlet,我想你可以声明一个上下文监听器 ,但是对于Spring MVC,Spring会让这个更简单吗?
此外,如果我定义一个上下文监听器,然后需要访问在我的servlet.xml
或applicationContext.xml
定义的bean,我将如何访问它们?
Spring有一些你可以处理的标准事件。
为此,您必须创build并注册一个实现ApplicationListener
接口的bean,如下所示:
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(...) // ... } } }
然后在servlet.xml
或applicationContext.xml
文件中注册这个bean:
<bean id="eventListenerBean" class="test.pack.age.ApplicationListenerBean" />
Spring会在应用上下文初始化时通知它。
在Spring 3中(如果您使用的是此版本), ApplicationListener
类是通用的 ,您可以声明您感兴趣的事件types,并相应地过滤该事件。 你可以像这样简化一下你的bean代码:
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); // now you can do applicationContext.getBean(...) // ... } }
从Spring 4.2开始,你可以使用@EventListener
( documentation )
@Component class MyClassWithEventListeners { @EventListener({ContextRefreshedEvent.class}) void contextRefreshedEvent() { System.out.println("a context refreshed event happened"); } }
创build您的注释
@Retention(RetentionPolicy.RUNTIME) public @interface AfterSpringLoadComplete { }
创build课堂
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) { } } } }
通过@Component注解或xml注册这个类
<bean class="ua.adeptius.PostProxyInvokerContextListener"/>
并且在上下文初始化之后使用任何想要运行的方法使用注释,如:
@AfterSpringLoadComplete public void init() {}
我有一个单一的页面应用程序inputURL它创build一个HashMap(由我的网页使用),其中包含来自多个数据库的数据。 我在服务器启动的时候,
1-创buildContextListenerClass
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-在web.xml中添加以下条目
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.context.listener.MyAppContextListener</listener-class> </listener>
3-在我的控制器类更新代码首先检查在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"; }
有了这个变化,当我启动我的tomcat时,它会在startTime中加载dataMap,并将所有内容放在servletContext中,然后由Controller Class使用它从已填充的servletContext中获取结果。