首页 > 代码库 > Spring的事件处理

Spring的事件处理

Spring对事件有一些支持,由于项目需要,所以最近小小研究了下到底这个怎么可以方便的用在实际项目当中来。

说起事件这个东西,其实就是借鉴的那个观察者模式。这里面涉及到事件源、事件监听者、事件发布者三个概念。

事件就是当我们修改一些数据之后,可能需要把这些修改后的数据告诉其他模块或者业务,使用事件后,当我修改了数据后,会发布一个事件。

那些关心我数据变化的,只需要继承BasicService并且事件源和我的一样,他就会收到这个事件的通知。这个,有个弊端就是多个事件源的时候,怎么通知。

以后再优化吧。先处理起简单的业务再说,慢慢来吧。

直接来例子比较好说一些,需要使用到Spring的jar包。


首先看底层封装的事件源。

package com.mine.event.basic.event;

import java.util.List;

import org.springframework.context.ApplicationEvent;

import com.mine.event.basic.enums.EventTypeEnum;

/**
  *
  * @author 2014-11-3 下午07:06:20 
  * @version V1.0  
 */
public class BasicEvent extends ApplicationEvent {
	
	/** * 序列化ID */
	private static final long serialVersionUID = 7519966952568731040L;

	public BasicEvent(Object object){
		super(object);
	}

	private EventTypeEnum eventTypeEnum;
	
	/**
	 * 事件通知的内容列表
	 */
	private List<?> eventList;

	/***
	 * 事件通知内容单个
	 */
	private Object eventObject;
	
	public void setEventList(List<?> eventList) {
		this.eventList = eventList;
	}

	public List<?> getEventList() {
		return eventList;
	}

	public void setEventTypeEnum(EventTypeEnum eventTypeEnum) {
		this.eventTypeEnum = eventTypeEnum;
	}

	public EventTypeEnum getEventTypeEnum() {
		return eventTypeEnum;
	}

	public void setEventObject(Object eventObject) {
		this.eventObject = eventObject;
	}

	public Object getEventObject() {
		return eventObject;
	}
}

然后就是事件监听者、事件发布者。

这里设计到一个类中的缘故是方便实现者。不需要实现者写那么多内容。

package com.mine.event.basic.service;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

import com.mine.event.basic.enums.EventTypeEnum;
import com.mine.event.basic.event.BasicEvent;
/**
  *
  * @author 2014-11-3 下午07:11:53 
  * @version V1.0  
 */
public abstract class BasicService<T extends BasicEvent> implements ApplicationContextAware,ApplicationListener<BasicEvent>{

	public abstract Class fetchCurrentEvent();
	
	private ApplicationContext applicationContext;
	
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}
	
	/**
	  * 增加单个对象并发布事件 
	  * @author 2014-11-5 上午09:15:25
	  * @param object 
	 */
	public void addSingleObj(Object object){
		
		Object event = getEventObject(object,EventTypeEnum.ADD);

		applicationContext.publishEvent((ApplicationEvent)event);
	}
	/** 通过反射实例化对象和设置事件类型
	  * @author  2014-11-5 上午11:53:39
	  * @param object
	  * @param eventTypeEnum 事件类型
	  * @return 
	 */
	@SuppressWarnings({ "rawtypes", "unchecked","finally" })
	private Object getEventObject(Object object,EventTypeEnum eventTypeEnum){
		//获取构造方法
		Object event = null;
		try {
			Class eventClass = fetchCurrentEvent();
			Constructor constructor = fetchCurrentEvent().getConstructor(Object.class);
			event = constructor.newInstance(this);
			//获取setEventObject方法
			Method method = eventClass.getMethod("setEventObject",Object.class);
			//调用setEventObject方法
			method.invoke(event,object);
			//获取设置事件枚举的方法
			Method enuMethod = eventClass.getMethod("setEventTypeEnum", EventTypeEnum.class); 
			enuMethod.invoke(event,eventTypeEnum);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}finally{
			return event;
		}
	}

	/***
	 * 需要实现者完成的具体事件内容
	  * @author 2014-11-5 上午09:14:58
	  * @param event 
	 */
	public abstract void notifyEvent(BasicEvent event);
	
	/**
	 *事件 
	 */
	@Override
	public void onApplicationEvent(BasicEvent event) {
		String eventString = event.getClass().toString();
		String currentString = fetchCurrentEvent().toString();
		//相同类型的事件才会进行通知
		if (eventString.equals(currentString)) {
			notifyEvent(event);
		}
	}
}


然后就是事件类型,采用枚举的方式,简单的分为增加、修改、删除。

package com.mine.event.basic.enums;
/**
  * 事件类型 
  * @author 2014-11-3 下午07:02:09 
  * @version V1.0  
 */
public enum EventTypeEnum {
	
	ADD,//增加
	DEL,//删除
	MODIFY//修改
}

下面进行例子的演示

首先定义一个实体User
package com.mine.event.entity;

/**
  *
  * @author 2014-11-3 下午06:59:26 
  * @version V1.0  
 */
public class User {

	private Integer id;
	
	private String name;
	
	public int getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public User(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

然后是事件源

package com.mine.event.event;

import com.mine.event.basic.event.BasicEvent;

/**
  * 用户相关事件
  * @author 2014-11-3 下午07:06:09 
  * @version V1.0  
 */
public class UserEvent extends BasicEvent{

	/** * 序列化ID */
	private static final long serialVersionUID = 7117267688533263478L;

	public UserEvent(Object object) {
		super(object);
	}
	
}
这个主要是对比用的。
package com.mine.event.event;

import com.mine.event.basic.event.BasicEvent;

public class TEvent extends BasicEvent {

	public TEvent(Object object) {
		super(object);
	}

}



然后是定义一个Service,而且它既是监听者又是发布者。
package com.mine.event.service;

import com.mine.event.basic.enums.EventTypeEnum;
import com.mine.event.basic.event.BasicEvent;
import com.mine.event.basic.service.BasicService;
import com.mine.event.entity.User;
import com.mine.event.event.UserEvent;

public class UserService extends BasicService<UserEvent> {

	/**
	 * 增加用户
	 * 
	 * @author 2014-11-3 下午07:18:16
	 * @param user
	 */
	public void addUser(User user) {
		this.addSingleObj(user);
	}
	
	/**
	 * 根据事件类型进行相应的处理
	 */
	@Override
	public void notifyEvent(BasicEvent event) {
			
			//如果UserEvent有自定义的属性或方法,下面需要调用的,则需要强制转换为UserEvent	
//			UserEvent userEvent = (UserEvent) event;
			
			EventTypeEnum typeEnum = event.getEventTypeEnum();
			
			User user = (User)event.getEventObject();
			if (user == null) {
				return;
			}
			switch (typeEnum) {
				case ADD:
					System.out.println("ADD:" + user.getName());
					break;
				case MODIFY:
					System.out.println("MODIFY:" + event.getEventObject());
					break;
				case DEL:
					System.out.println("DEL:" + event.getEventObject());
					break;
				default:
					System.out.println("其它");
					break;
			}
	}

	@Override
	public Class fetchCurrentEvent() {
		return UserEvent.class;
	}
}

下面的和这个主要是用来对比的,因为这个事件源是TEvent。所以UserEvent事件发生后,UserServiceTemp不会收到通知。
因为BasicService在进行事件通知时会比对事件源是否一样,一样的才会进行通知。
package com.mine.event.service;

import com.mine.event.basic.enums.EventTypeEnum;
import com.mine.event.basic.event.BasicEvent;
import com.mine.event.basic.service.BasicService;
import com.mine.event.entity.User;
import com.mine.event.event.TEvent;

public class UserServiceTemp  extends BasicService<TEvent>{

	/**
	 * 增加用户
	 * 
	 * @author 2014-11-3 下午07:18:16
	 * @param user
	 * @modificationHistory=========================逻辑或功能性重大变更记录
	 * @modify by user: {修改人} 2014-11-3
	 * @modify by reason:{原因}
	 */
	public void addUser(User user) {
		this.addSingleObj(user);
	}
	
	/**
	 * 根据事件类型进行相应的处理
	 */
	public void notifyEvent(BasicEvent event) {
			
			//如果UserEvent有自定义的属性或方法,下面需要调用的,则需要强制转换为UserEvent	
//			UserEvent userEvent = (UserEvent) event;
			
			EventTypeEnum typeEnum = event.getEventTypeEnum();
			
			User user = (User)event.getEventObject();
			if (user == null) {
				return;
			}
			switch (typeEnum) {
				case ADD:
					System.out.println("UserServiceTempADD:" + user.getName());
					break;
				case MODIFY:
					System.out.println("MODIFY:" + event.getEventObject());
					break;
				case DEL:
					System.out.println("DEL:" + event.getEventObject());
					break;
				default:
					System.out.println("其它");
					break;
			}
	}

	public Class fetchCurrentEvent() {
		return TEvent.class;
	}
}

下面是Sping的一些配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
		
	<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
	<bean id="userServiceImpl" class="com.mine.event.service.UserService" />
	<bean id="userServiceTemp" class="com.mine.event.service.UserServiceTemp" />
</beans>

最后是一个测试类
package com.mine.event.test;

import java.util.Collection;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mine.event.basic.service.BasicService;
import com.mine.event.entity.User;
import com.mine.event.service.UserService;

public class TestUserEvent {
	
	public static void main(String[] args) {
		
		User user = new User(1,"name_1");
		
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		UserService userService = applicationContext.getBean("userServiceImpl",UserService.class);
		
		userService.addUser(user);
		
		Collection<BasicService> collection = applicationContext.getBeansOfType(BasicService.class).values();
		
		//通过Spring可以获得所有加载到Spring上下文中的一个类的子类。
		System.out.println("获取BasicService的所有加载到Spring上下文当中的所有子类个数"+collection.size());
	}
}






Spring的事件处理