基于SpringBoot和注解实现优雅的事件监听器
2019-11-12 本文已影响0人
曾泽浩
1. 了解事件监听器
事件监听器包括3个部分,事件、事件源、事件监听器。
事件,主要用于传递参数,例如用户登录,可以传递用户的名字等参数。
事件源,就是触发监听的方法或事件,用于抛出一个事件,通知事件监听器。
事件监听器,监听某个事件,接收到这个事件后,处理相应的逻辑。
2. 监听器的处理流程
- 给事件注册监听
- 触发某个事件
- 触发的事件通知对应的监听器,传递事件参数
- 事件监听器处理对应的逻辑
3. 基于SpringBoot和注解实现优雅的事件监听器
-
定义事件
IEvent
事件的抽象接口,用于传递事件参数public interface IEvent { }
-
定义事件监听处理器
IEventListener
事件触发监听后,处理对应的逻辑public interface IEventListener { void handle(IEvent event); }
-
定义
@Listener
和@EventAnno
用于自动注册事件@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Listener { }
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface EventAnno { }
-
定义监听方法处理器
EventMethodListener
用反射调用触发的监听方法public class EventMethodListener implements IEventListener { private Class<?> eventClass; private Object invoker; private Method method; public EventMethodListener(Class<?> eventClass, Object invoker, Method method) { this.eventClass = eventClass; this.invoker = invoker; this.method = method; } @Override public void handle(IEvent event) { try { method.invoke(invoker, event); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public Class<?> getEventClass() { return eventClass; } public void setEventClass(Class<?> eventClass) { this.eventClass = eventClass; } public Object getInvoker() { return invoker; } public void setInvoker(Object invoker) { this.invoker = invoker; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } }
-
定义事件处理中心,统一处理事件的注册,事件触发后通知事件监听器。
Component public class EventBus implements ApplicationContextAware { private Logger logger = LoggerFactory.getLogger(EventBus.class); private ApplicationContext applicationContext; private static EventBus instance; private Map<Class<?>, List<IEventListener>> listenerMap = new HashMap<>(); public static EventBus getInstance() { return instance; } @PostConstruct public void init() { instance = this; initListeners(); } /** * 自动注册 */ private void initListeners() { Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Listener.class); beans.values().forEach(this::register); } /** * 注册用@Listener注解的bean,扫描所有用@EventAnno注解的方法 * @param object */ public void register(Object object) { Method[] declaredMethods = object.getClass().getDeclaredMethods(); for (Method method : declaredMethods) { EventAnno annotation = method.getAnnotation(EventAnno.class); if (annotation == null) { continue; } if (!Modifier.isPublic(method.getModifiers())) { logger.error("The Listener Method Modifier Must be public" + method.getName()); continue; } checkListenerMethod(method); Class<?> eventClass = method.getParameterTypes()[0]; EventMethodListener eventMethodListener = new EventMethodListener(eventClass, object, method); addListener(eventMethodListener); } } private void checkListenerMethod(Method method) { if (method.getParameterTypes().length != 1) { throw new IllegalArgumentException("The method params wrong on" + method.getName() + ", The method params length need equals 1"); } if (!IEvent.class.isAssignableFrom(method.getParameterTypes()[0])) { throw new IllegalArgumentException("The method params wrong on" + method.getName() + ", The method params need to subClass of IEvent"); } } /** * 事件触发后通知事件监听器 * @param event */ public void fire(IEvent event) { Class<?> clz = event.getClass(); while (clz != Object.class && clz != null) { List<IEventListener> listeners = listenerMap.get(clz); if (listeners != null) { listeners.forEach(listener -> handleListener0(listener, event)); } clz = clz.getSuperclass(); } } /** * 处理对应的逻辑 * @param listener * @param event */ private void handleListener0(IEventListener listener, IEvent event) { listener.handle(event); } private void addListener(EventMethodListener listener) { List<IEventListener> listeners = listenerMap.computeIfAbsent(listener.getEventClass(), a -> new ArrayList<>()); listeners.add(listener); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
-
定义一个测试事件
public class TestEvent implements IEvent { private int id; public TestEvent(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
-
定义用于处理监听事件的Listener
@Listener @Component public class TestListener { @EventAnno public void testEvent(TestEvent event) { int id = event.getId(); System.out.println("+++++++++" + id); } @EventAnno private void testEvent1(TestEvent event) { int id = event.getId(); System.out.println("testEvent1" + id); } }
-
最后启动类,抛出对应的事件
@SpringBootApplication public class EventApplication { public static void main(String[] args) { SpringApplication.run(EventApplication.class, args); EventBus.getInstance().fire(new TestEvent(22222)); } }
谢谢大家,有错误或者不理解的地方,方法大家纠正讨论。