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);/***事件 */@Overridepublic 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);}/*** 根据事件类型进行相应的处理*/@Overridepublic 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;}}@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aophttp://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的事件处理相关推荐

  1. 【Java】Spring 教程

    Spring 教程 Spring 概述 三层架构 Spring 的优良特性 使用 Spring 框架的好处 依赖注入(DI) Spring 框架具有以下几个特点: 1)方便解耦,简化开发 2)方便集成 ...

  2. Spring源码之The IoC container官方文档翻译

    官方文档:https://docs.spring.io/spring/docs/4.3.21.RELEASE/spring-framework-reference/htmlsingle/#beans ...

  3. Spring框架常见面试题

    1. 你对Spring框架的理解(特点)? Spring框架有哪些模块 ? Spring,一种用来简化企业应用级开发的一种开源框架. 简化开发:它对常用的API做了封装,比如对JDBC的封装,使用Sp ...

  4. spring core之Ioc介绍

    1.ApplicationContext是BeanFactory的子接口. 2.BeanFactory提供配置框架和基本功能,ApplicationContext添加更多特定于企业的功能. 3.org ...

  5. JAVA经典面试题汇总(保存这篇就够了)

    一. java基础篇 1.final 关键字的作用? 被 final 修饰的类不可以被继承. 被 final 修饰的方法不可以被重写. 被 final 修饰的变量不可以被改变,如果修饰引用,那么表示引 ...

  6. Spring 中的事件处理

    Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期.当加载 beans 时,ApplicationContext 发布某些类型的事件.例如,当上下文启 ...

  7. Spring 中的如何自定义事件处理(Custom Event)

    新建一个CustomEvent.java: import org.springframework.context.ApplicationEvent; public class CustomEvent ...

  8. 3W 字的 Spring Boot 超详细总结

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者|CHEN川 http://www.jianshu.c ...

  9. 最棒 Spring Boot 干货总结(超详细,建议收藏)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:CHEN川 链接:http://www.jianshu.co ...

  10. Spring Boot 2.3.0 新特性:优雅停机!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 前言:关于Spring Boot.Spring Cloud应用的优 ...

最新文章

  1. 如何从sdcard读取文件
  2. SAP物料价格评估与成本计算体系
  3. mysql 平均月份_Mysql按月份统计和按时段统计SQL
  4. java3d 上色_Unity 着色过程
  5. spring mvc学习(43):处理静态资源
  6. 用Python绘制一套“会跳舞”的动态图形给你看看
  7. 首次!阿里达摩院将Pure Transformer 应用于目标重识别ReID!
  8. 通过这次源码分析直播了解到在中国真正关心源码的webrtc开发者只有1%
  9. win7操作系统练习题(带答案,有问题可直接在博客或公众号中问)
  10. libhv网络库源码剖析
  11. php给超链接添加图标,怎么给一个PHP密码访问页面加超链接
  12. 【CS61A】学习笔记
  13. spring boot启动报错:Reason: Canonical names should be kebab-case (‘-‘ separated), lowercase
  14. django基础入门之搭建博客系统
  15. dnf台服空白mysql文件夹_关于雨泪大神的架设教程遇到的各种问题的解决办法
  16. TS科普19 各种流(如:MP3、H264、H265等)在TS的流类型
  17. 【EXP】函数使用技巧
  18. JAVA毕业设计国产精品动漫网站计算机源码+lw文档+系统+调试部署+数据库
  19. 关于MBP(苹果MAC)终端输入su命令出现Sorry提示的解决办法
  20. Python第三方库tabulate简单使用说明

热门文章

  1. 入门学习计算机第十三天—初识指针
  2. JS实现网页打印功能
  3. 【实习面经】头条后台开发岗一面凉经
  4. EBS 报表开发:XML Publisher
  5. C/C++中va_start/va_arg/va_end函数源码文件位置及实现原理
  6. 如何判断一个点在三角形内部
  7. YUV420P与YUVJ420P
  8. 怎样把pdf格式转换成jpg
  9. JDBC Driver介绍
  10. php各版本共存方法,PHP多版本共存解决方案图解