本文是运用观察者模式,不清楚的伙伴们可以先看基础篇:https://blog.csdn.net/yk614294861/article/details/86493056
近期在做一个门禁系统,该门禁系统需要对接很多人脸开门的设备厂家,默认系统中有一个主流程是开卡,由于之前小伙伴门,每次对接一个厂家都在主流程中增加几行代码,引入需要增加的厂商服务类,这种操作代码严重耦合,经常改动原本完整的代码。因此对此进行改善,使用观察者模式进行代码解耦和,在开卡的时候进行事件统一分发,后续增加厂商仅仅需要监听具体事件即可,不用再去改动原本的代码。
1.定义事件总线,统一管理事件的注册、移除、分发
package com.summerSpringBoot.observer;
public interface IEventHub {
public static final String name = "IEventHub";
/**
* @Title: registListener
* @Description: 事件注册
* @param eventType 事件类型
* @param listener 绑定监听器
* @return: void
* @throws
*/
public void registListener(EventType eventType, IListener listener);
/**
* @Title: removeListener
* @Description: 移除监听器
* @param eventType 事件类型
* @param listener 监听器
* @return: void
* @throws
*/
public void removeListener(EventType eventType, IListener listener);
/**
* @Title: dispatchEvent
* @Description: 事件分发
* @param eventType 事件类型
* @param event 具体事件
* @return: void
* @throws
*/
public void dispatchEvent(EventType eventType, Event event);
}
2.定义统一的监听器接口
package com.summerSpringBoot.observer;
public interface IListener {
/**
* @Title: onEvent
* @Description: 监听器接口
* @param type 事件类型
* @param event 具体事件
* @throws Exception
* @return: void
* @throws
*/
public void onEvent(EventType type, Event event) throws Exception;
}
3.事件总线的实现类
package com.summerSpringBoot.observer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@Component
public class EventHub implements IEventHub {
private static Logger logger = Logger.getLogger(EventHub.class);
private Map<EventType, ArrayList<IListener>> eventTable = new HashMap<>();
@Override
public void registListener(EventType eventType, IListener listener) {
ArrayList<IListener> listenerList = this.eventTable.get(eventType);
if (listenerList == null) {
listenerList = new ArrayList<IListener>();
this.eventTable.put(eventType, listenerList);
}
listenerList.add(listener);
}
@Override
public void removeListener(EventType eventType, IListener listener) {
ArrayList<IListener> listenerList = this.eventTable.get(eventType);
if(listenerList!=null &&listenerList.size()>0 ){
listenerList.remove(listener);
}
}
@Override
public void dispatchEvent(EventType eventType, Event event) {
ArrayList<IListener> listenerList = this.eventTable.get(eventType);
for (IListener iListener : listenerList) {
try {
iListener.onEvent(eventType, event);
} catch (Exception e) {
logger.error("执行监听器出错" + iListener, e);
}
}
}
}
3.定义枚举类,表示事件类型
package com.summerSpringBoot.observer;
/**
* @ClassName: EventType
* @Description:事件枚举类,表示事件类型,可扩展
* @author: summer
* @date: 2018年12月19日 下午5:03:45
*
*/
public enum EventType {
/**
* @Fields FLOW_TYPE_NEW : 新办卡
*/
FLOW_TYPE_NEW,
/**
* @Fields FLOW_TYPE_ADD : 补卡
*/
FLOW_TYPE_ADD,
/**
* @Fields FLOW_TYPE_HOUSE_ADD : 新增房屋
*/
FLOW_TYPE_HOUSE_ADD,
/**
* @Fields FLOW_TYPE_HOUSE_DESTROY : 销卡
*/
FLOW_TYPE_HOUSE_DESTROY
}
4.自定义注解,用在类上,这样可以方便地注册事件
package com.summerSpringBoot.observer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName: EventListener
* @Description:自定义注解标注注册是事件类型
* @author: summer
* @date: 2019年1月15日 下午3:42:46
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventListener {
EventType[] eventType();
}
5.Spring 初始化地时候一起注册事件,大概流程是,当InitRegistListeners类初始化完成后会执行@PostConstruct标注地registListener() 方法,可以从Spring中获取所有IListener接口地实现类,然后获取类上地注解,并注册到事件总线
package com.summerSpringBoot.observer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class InitRegistListeners {
@Autowired
private EventHub eventHub;
@Autowired
private SpringContextHolder springContextHolder;
private static Logger logger = Logger.getLogger(InitRegistListeners.class);
@PostConstruct
public void registListener() {
logger.info("##############开始注册监听器###############");
Map<String, IListener> map = springContextHolder.getMap();
for (Map.Entry<String, IListener> obj : map.entrySet()) {
IListener listener = obj.getValue();
Class<? extends IListener> class1 = listener.getClass();
Annotation annotation = class1.getAnnotation(EventListener.class);
if (null != annotation) {
try {
Method method = annotation.annotationType().getDeclaredMethod("eventType");
EventType[] types = (EventType[]) method.invoke(annotation, null);
for (EventType type : types) {
eventHub.registListener(type, listener);
logger.info("监听器" + obj.getKey() + "注册成功,监听事件:" + type + "---" + listener);
}
} catch (Exception e) {
logger.error(listener + "监听器注册失败", e);
}
}
}
}
}
6.自定义SpringContextHolder implements ApplicationContextAware 使用getBeansOfType方法,根据接口类型返回相应的所有bean,也就是获取所有实现IListener接口的类,key为bean的id.value 为实现类对象
package com.summerSpringBoot.observer;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
private Map<String, IListener> map;
/**
* 获取静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
//根据接口类型返回相应的所有bean,也就是获取所有实现IListener接口的类,key为bean的id.value 为实现类对象
map = applicationContext.getBeansOfType(IListener.class);
}
public Map<String, IListener> getMap(){
return map;
}
}
7.定义监听器实现类处理具体地逻辑,例如旷视地人脸注册
package com.summerSpringBoot.demo.listener;
import org.springframework.stereotype.Service;
import com.summerSpringBoot.observer.Event;
import com.summerSpringBoot.observer.EventListener;
import com.summerSpringBoot.observer.EventType;
import com.summerSpringBoot.observer.IListener;
@EventListener(eventType=EventType.FLOW_TYPE_NEW)
@Service
public class UserCreateListener implements IListener {
@Override
public void onEvent(EventType type, Event event) throws Exception {
System.out.println("UserCreateListener执行了,旷视注册人脸");
}
}
8.事件分发使用 UserEvent 是继承Event类地一个子类,使用该类来携带必须地参数。经过dispatchEvent后,指定地事件类型监听器就会执行
执行后地
具体demo代码如附件:https://download.csdn.net/download/yk614294861/10918876