原文链接:
1 Spring 监听事件 ApplicationListener 和 ApplicationEvent
http://blog.csdn.net/ilovejava_2010/article/details/7953419
2 在springboot中如何配置,及二次调用的解决
http://blog.csdn.net/wo541075754/article/details/71720984
1
什么是ApplicationContext?
它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些。
ApplicationContext则是应用的容器。
Spring把Bean(object)放在容器中,需要用就通过get方法取出来。
ApplicationEvent
是个抽象类,里面只有一个构造函数和一个长整型的timestamp。
ApplicationListener
是一个接口,里面只有一个onApplicationEvent方法。
所以自己的类在实现该接口的时候,要实装该方法。
如果在上下文中部署一个实现了ApplicationListener接口的bean,
那么每当在一个ApplicationEvent发布到 ApplicationContext时,
这个bean得到通知。其实这就是标准的Oberver设计模式。
下面给出例子:
首先创建一个ApplicationEvent实现类:
- package com.spring.event;
-
- import org.springframework.context.ApplicationEvent;
-
- /**
- * <p>Class:EmailListEvent</p>
- * <p>Description:</p>
- * @author Liam
- * @Date [2012-9-7 上午8:42:07]
- */
- public class EmailEvent extends ApplicationEvent {
- /**
- * <p>Description:</p>
- */
- private static final long serialVersionUID = 1L;
- public String address;
- public String text;
-
- public EmailEvent(Object source) {
- super(source);
- }
-
- public EmailEvent(Object source, String address, String text) {
- super(source);
- this.address = address;
- this.text = text;
- }
-
- public void print(){
- System.out.println("hello spring event!");
- }
-
- }
给出监听器:
- package com.spring.event;
-
- import org.springframework.context.ApplicationEvent;
- import org.springframework.context.ApplicationListener;
-
- /**
- * <p>Class:EmailListener</p>
- * <p>Description:</p>
- * @author Liam
- * @Date [2012-9-7 上午8:44:53]
- */
- public class EmailListener implements ApplicationListener {
-
- public void onApplicationEvent(ApplicationEvent event) {
- if(event instanceof EmailEvent){
- EmailEvent emailEvent = (EmailEvent)event;
- emailEvent.print();
- System.out.println("the source is:"+emailEvent.getSource());
- System.out.println("the address is:"+emailEvent.address);
- System.out.println("the email's context is:"+emailEvent.text);
- }
-
- }
-
- }
applicationContext.xml文件配置:
<bean id="emailListener" class="com.spring.event.EmailListener"></bean>
测试类:
- package com.spring.event;
-
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- /**
- * <p>Class:Test</p>
- * <p>Description:</p>
- * @author Liam
- * @Date [2012-9-6 上午10:41:34]
- */
- public class Test {
- public static void main(String[] args) {
- ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
-
- //HelloBean hello = (HelloBean) context.getBean("helloBean");
- //hello.setApplicationContext(context);
- EmailEvent event = new EmailEvent("hello","boylmx@163.com","this is a email text!");
- context.publishEvent(event);
- //System.out.println();
- }
- }
- <pre class="html" name="code">hello spring event!
- the source is:hello
- the address is:boylmx@163.com
- the email's context is:this is a email text!
- </pre>
- <pre></pre>
-
2
使用场景
在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载、初始化缓存、特定任务的注册等等。这个时候我们就可以使用Spring提供的ApplicationListener来进行操作。
用法
本文以在Spring boot下的使用为例来进行说明。首先,需要实现ApplicationListener接口并实现onApplicationEvent方法。把需要处理的操作放在onApplicationEvent中进行处理:
package com.secbro.learn.context
import org.springframework.context.ApplicationListener
import org.springframework.context.event.ContextRefreshedEvent
public class ApplicationStartListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("我的父容器为:" + contextRefreshedEvent.getApplicationContext().getParent())
System.out.println("初始化时我被调用了。")
}
}
然后,实例化ApplicationStartListener这个类,在Spring boot中通过一个配置类来进行实例化:
package com.secbro.learn.conf;
import com.secbro.learn.context.ApplicationStartListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by zhuzs on 2017/5/12.
*/
@Configuration
public class ListenerConfig {
@Bean
public ApplicationStartListener applicationStartListener(){
return new ApplicationStartListener();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
随后,启动Spring boot服务,打印出一下内容:
我的父容器为:null
初始化时我被调用了。
从打印的结果可以看出,ApplicationStartListener的onApplicationEvent方法在容器启动时已经被成功调用了。而此时初始化的容器为root容器。
二次调用问题
此处使用Spring boot来进行操作,没有出现二次调用的问题。在使用传统的application.xml和project-servlet.xml配置中会出现二次调用的问题。主要原因是初始化root容器之后,会初始化project-servlet.xml对应的子容器。我们需要的是只执行一遍即可。那么上面打印父容器的代码用来进行判断排除子容器即可。在业务处理之前添加如下判断:
if(contextRefreshedEvent.getApplicationContext().getParent() != null){
return;
}
这样其他容器的初始化就会直接返回,而父容器(Parent为null的容器)启动时将会执行相应的业务操作。
关联知识
在spring中InitializingBean接口也提供了类似的功能,只不过它进行操作的时机是在所有bean都被实例化之后才进行调用。根据不同的业务场景和需求,可选择不同的方案来实现。