ApplicationContext具有发布事件的能力。这是因为该接口继承了ApplicationEventPublisher接口。Spring中与事件有关的接口和类主要包括ApplicationEvent、ApplicationListener。
定义一个事件的类需要继承ApplicationEvent或者ApplicationContextEvent抽象类,该抽象类中只有一个构造函数,并且带有一个Object类型的参数作为事件源,并且该事件源不能为null,因此我们需要在自己的构造函数中执行super(Object)。
public class UserEvent extends ApplicationEvent
{
private String eventContent;
public String getEventContent(){
return eventContent;
}
public void setEventContent(String eventContent){
this.eventContent = eventContent;
}
public UserEvent(Object source,String eventContent){
super(source);
this.eventContent = eventContent;
}
}
针对一种事件,可能需要特定的监听器,因此,监听器需要实现ApplicationListener接口。当监听器接收到一个事件的时候,就会执行它的onApplicationEvent()方法。由于Spring IoC中的事件模型是一种简单的、粗粒度的监听模型,当有一个事件到达时,所有的监听器都会接收到,并且作出响应,如果希望只针对某些类型进行监听,需要在代码中进行控制。
public class UserListener implements ApplicationListener
{
public void onApplicationEvent(ApplicationEvent event){
if(event instanceof UserEvent){ //只对UserEvent类型进行处理
UserEvent ue = (UserEvent)event;
String result = ue.getEventContent();
System.out.println("Event Content:"+result);
}
}
}
对于发布事件,我们可以实现ApplicationContextAware或者ApplicationEventPublisherAware接口。
public class UserBiz implements ApplicationContextAware
{
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
public void service(String thing)
{
UserEvent event = new UserEvent(this,thing);
event.setEventContent("I shoud "+thing);
applicationContext.publishEvent(event);
}
}
或者如下:
public class UserBiz2 implements ApplicationEventPublisherAware
{
private ApplicationEventPublisher applicationEventPublisher;
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
{
this.applicationEventPublisher = applicationEventPublisher;
}
public void service(String thing)
{
UserEvent event = new UserEvent(this,thing);
event.setEventContent("I shoud "+thing);
applicationEventPublisher.publishEvent(event);
}
}
至此便完成了事件的发布,当ApplicationContext接收到事件后,事件的广播是Spring内部给我们做的,不需要了解具体的细节。其实在Spring读取配置文件之后,利用反射,将所有实现ApplicationListener的Bean找出来,注册为容器的事件监听器。当接收到事件的时候,Spring会逐个调用事件监听器。剩下要做的就是在配置文件中配置监听器。
<bean class="footprint.spring.ioc.event.UserListener"/>
Spring容器自身会发布一些事件,包括ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent。
LockedIPEvent.java
- package com.gjx.spring.event;
- import org.springframework.context.ApplicationEvent;
- public class LockedIPEvent extends ApplicationEvent {
- public LockedIPEvent(Object source) {
- super(source);
- }
- }
LockedIPListener.java
- package com.gjx.spring.event;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.context.ApplicationEvent;
- import org.springframework.context.ApplicationListener;
- public class LockedIPListener implements ApplicationListener {
- //在这里,监听器应该只作一个记录功能
- private Log logger=LogFactory.getLog(LockedIPListener.class);
- public void onApplicationEvent(ApplicationEvent event) {
- if (event instanceof LockedIPEvent) {
- logger.info("Locked IP ["+event.getSource()+"] try to login !");
- }
- }
- }
UserManager.java
- package com.gjx.spring.event;
- import java.util.List;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- /*实现啦这个接口就会通过ApplicationContext来取得 这是一个接口的注入
- * 如果使用这样的事件就会和Spring 偶合在一起啦
- *
- */
- public class UserManager implements ApplicationContextAware {
- private List lockedIPList;
- private ApplicationContext context;
- public List getLockedIPList() {
- return lockedIPList;
- }
- public void setLockedIPList(List lockedIPList) {
- this.lockedIPList = lockedIPList;
- }
- public boolean isLogin(String username,String password,String ip){
- if(lockedIPList.contains(ip)){
- context.publishEvent(new LockedIPEvent(ip)); //发布这个事件
- return true;
- }
- return false;
- }
- public void setApplicationContext(ApplicationContext context) throws BeansException {
- this.context=context;
- }
- }
beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
- <beans>
- <!-- 监听器类的ID设不设置都无所谓 ,如果不想要日志信息,直接删掉下面这句就OK啦。所以很方便-->
- <bean class="com.gjx.spring.event.LockedIPListener"/>
- <bean id="userManager" class="com.gjx.spring.event.UserManager">
- <property name="lockedIPList">
- <list>
- <value>222.111.111.4</value>
- <value>222.111.111.7</value>
- <value>222.111.111.9</value>
- </list>
- </property>
- </bean>
- </beans>
JUnit的测试代码
TestSpring.java
- package Test.com.gjx.spring;
- import java.io.BufferedOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Date;
- import java.util.Locale;
- import junit.framework.TestCase;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.context.support.GenericApplicationContext;
- import org.springframework.core.io.Resource;
- import com.gjx.spring.HelloAction;
- import com.gjx.spring.event.UserManager;
- public class TestSpring extends TestCase {
- public void testEvent() {
- ApplicationContext context = new ClassPathXmlApplicationContext(
- "beans.xml");
- UserManager userManager = (UserManager) context.getBean("userManager");
- userManager.isLogin("冬国", "1234567", "222.111.111.4");
- }
- }