Spring 如何向应用程序上下文初始化事件添加挂钩?

Spring 如何向应用程序上下文初始化事件添加挂钩?,spring,model-view-controller,applicationcontext,Spring,Model View Controller,Applicationcontext,对于一个普通的Servlet,我想您可以声明一个,但是对于SpringMVC,Spring会使这更容易吗 此外,如果我定义了一个上下文侦听器,然后需要访问在我的servlet.xml或applicationContext.xml中定义的bean,我将如何访问它们 为此,必须创建并注册一个实现ApplicationListener接口的bean,如下所示: package test.pack.age; import org.springframework.context.ApplicationC

对于一个普通的Servlet,我想您可以声明一个,但是对于SpringMVC,Spring会使这更容易吗

此外,如果我定义了一个上下文侦听器,然后需要访问在我的
servlet.xml
applicationContext.xml
中定义的bean,我将如何访问它们

为此,必须创建并注册一个实现
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(...)
            // ...
        }
    }
}
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        // now you can do applicationContext.getBean(...)
        // ...
    }
}
然后在
servlet.xml
applicationContext.xml
文件中注册此bean:

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

从Spring4.2开始,您可以使用
@EventListener
()


我在输入URL时有一个单页应用程序,它正在创建一个HashMap(由我的网页使用),其中包含来自多个数据库的数据。 在服务器启动期间,我执行了以下操作来加载所有内容-

1-已创建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);

    }
公共类MyAppContextListener实现ServletContextListener
@自动连线
私有MyDataProviderBean MyDataProviderBean;
公共MyDataProviderBean getMyDataProviderBean(){
返回MyDataProviderBean;
}
public void setMyDataProviderBean(MyDataProviderBean MyDataProviderBean){
this.myDataProviderBean=myDataProviderBean;
}
@凌驾
公共无效上下文已销毁(ServletContextEvent arg0){
System.out.println(“ServletContextListener已销毁”);
}
@凌驾
公共void contextInitialized(ServletContextEvent上下文){
System.out.println(“ServletContextListener已启动”);
ServletContext sc=context.getServletContext();
WebApplicationContext springContext=WebApplicationContextils.getWebApplicationContext(sc);
MyDataProviderBean MyDataProviderBean=(MyDataProviderBean)springContext.getBean(“MyDataProviderBean”);
Map 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>

org.springframework.web.context.ContextLoaderListener
com.context.listener.MyAppContextListener
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";

        }
@RequestMapping(value=“/index”,method=RequestMethod.GET)
公共字符串索引(@modeldattribute(“model”)ModelMap model){
Map myDataMap=newhashmap();
if(context!=null&&context.getAttribute(“myMap”)!=null)
{
myDataMap=(Map)context.getAttribute(“myMap”);
}
其他的
{
myDataMap=myDataProviderBean.getDataMap();
}
for(字符串键:myDataMap.keySet())
{
addAttribute(key,myDataMap.get(key));
}
返回“我的网页”;
}
当我启动tomcat时,它会在startTime期间加载数据映射,并将所有内容放入servletContext中,然后控制器类使用它从已填充的servletContext中获取结果。

创建注释

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

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

请按照以下步骤在加载应用程序上下文(即应用程序已准备就绪)后进行一些处理

  • 创建以下注释,即

    @保留(RetentionPolicy.RUNTIME) @目标(值={ElementType.METHOD,ElementType.TYPE}) public@interface AfterApplicationReady{}

  • 2.在下面创建一个类,该类是在应用程序就绪状态下获取调用的侦听器

        @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);
            }
        }
    }
    
    @组件
    公共类PostApplicationReadyListener实现ApplicationListener{
    公共静态最终记录器Logger=LoggerFactory.getLogger(PostApplicationReadyListener.class);
    公共静态最终字符串模块=PostApplicationReadyListener.class.getSimpleName();
    @凌驾
    ApplicationEvent上的公共无效(ApplicationReadyEvent事件){
    试一试{
    ApplicationContext context=event.getApplicationContext();
    String[]beans=context.getBeanNamesForAnnotation(AfterAppStarted.class);
    info(“使用AfterAppStarted注释找到的bean是:{}”,Arrays.toString(bean));
    for(字符串bean名称:bean){
    objectbean=context.getBean(beanName);
    Class targetClass=AopUtils.getTargetClass(bean);
    方法[]methods=targetClass.getMethods();
    用于(方法:方法){
    if(方法.isAnnotationPresent(AfterAppStartedComplete.class)){
    info(“使用AfterAppStartedComplete注释找到的Bean:{}的方法:[{}”,Method.getName(),beanName);
    方法currentMethod=bean.getClass().getMethod(方法.getName(),方法.getParameterTypes());
    info(“将调用bean:{},method.getName(),beanName的方法:{}”);
    调用(bean);
    info(“bean的调用完成方法:{}”,method.getName(),beanName);
    }
    }
    }
    }捕获(例外e){
    LOGGER.warn(“发生异常:”,e);
    }
    }
    }
    

    最后,当您在日志声明应用程序启动之前启动Spring应用程序时,将调用您的侦听器。

    好的,谢谢。很高兴知道spring3过滤了这些事件。我以前确实注意到applicationlistener类。但是它的钩子也会为RequestHandledEvent调用。你知道如果你使用注释的东西并声明两个类会发生什么吗?非注释(XML)和两个?他们会按照宣布的顺序开火吗?谢谢;)仅供参考,context start的事件是ContextStartedEvent Docs:-@Kumar Sambhav:这是正确的,但也必须提到它们之间的差异。请参见此处:和此处:from:“从Spring3.0开始,ApplicationListener可以通用地声明
    <bean class="ua.adeptius.PostProxyInvokerContextListener"/>
    
       @AfterSpringLoadComplete
        public void init() {}
    
        @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);
            }
        }
    }