基于SpringBoot和注解实现优雅的事件监听器

作者: 曾泽浩 | 来源:发表于2019-11-12 12:27 被阅读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));
          }
      
      }
      

    谢谢大家,有错误或者不理解的地方,方法大家纠正讨论。

    最后附上传送门,https://github.com/Zengzehao/easy-event

    相关文章

      网友评论

        本文标题:基于SpringBoot和注解实现优雅的事件监听器

        本文链接:https://www.haomeiwen.com/subject/evwfictx.html