一、 什么是监听事件

在程序执行过程中对某一个功能或者事件进行监听。例如,用户登录成功后,发送短信或者邮件信息给用户。

二、如何完成监听事件

监听事件是基于观察者模式实现的,要完成监听事件,需要准备好,事件源、事件监听器和发布事件,实现上诉三个条件,就可以实现事件监听了。

三、监听事件实现

  1. 基于Spring 框架实现

事件源信息

import org.springframework.context.ApplicationEvent;
/**
 * 基于Spring框架实现的事件监听
 * 
 * 事件源,自定义一个事件源,具体的内容更具具体的业务进行实现。
 */
public class CustomEven extends ApplicationEvent {

    public CustomEven(Object source) {
        super(source);
    }

}

事件监听器

/**
 * 基于Spring框架实现的事件监听
 *
 * 事件监听器, 监听到指定的事件后,会触发的方法
 */
@Component
public class CustomListener implements ApplicationListener<CustomEven> {

    /**
     * 监听到事件触发后,执行的方法
     * @param customEven
     */
    @Override
    public void onApplicationEvent(CustomEven customEven) {
        System.out.println("==== 发送用户登录成功邮件 ==== ");
    }
}

发布事件监听器

@RestController
public class TestController {

    /**
     * 基于 spring 的事件监听器,需要使用 applicationContext 进行发布处理
     */
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 基于Spring框架实现的事件监听
     */
    @RequestMapping("/app/login")
    public void login() {
        System.out.println("==== 用户登录成功 ====");
        System.out.println("--------------------------------");
        // 事件源信息
        CustomEven customEven = new CustomEven(this);
        // 发布事件
        applicationContext.publishEvent(customEven);
    	}
    }
  1. 自定义实现

基础事件类

/**
* 自定义事件监听
* 自定义注解中 事件的父类,后面定义的事件类都要基础这个类
*/
public class ApplicationEven {
}

基础监听器类

/**
 * 自定义事件监听器中
 * 事件监听器接口
 */
public interface ApplicationListener<E extends ApplicationEven> {

    void onEven(E e);
}

事件发布类,下面是不使用spring的框架进行监听器注册,基于spring框架的可以修改代码修改监听器的注册方式;

public class ListenerHandler {

    private static List<ApplicationListener> listenerList;


    /**
     *    自定义使用该方法进行添加,如果配合 spring框架,可以不使用该方法,
     * 直接使用 注解进行注册即可
     * @param listener
     */
    public static void addListener(ApplicationListener listener) {
        listenerList.add(listener);
    }

    /**
     * 进行事件的发布
     * @param applicationEven
     */
    public static void publishEvent(ApplicationEven applicationEven) {
        for (ApplicationListener listener : listenerList) {

            // 获取监听器中监听的事件
            Class clazz = (Class)((ParameterizedType)listener.getClass().getGenericInterfaces()[0])
                    .getActualTypeArguments()[0];

            // 事件相同时,触发监听方法
            if (applicationEven.getClass().equals(clazz)) {
                // 进行事件
                listener.onEven(applicationEven);
            }
        }
    }
}
事件源信息
public class CustomEven extends ApplicationEven {
    public CustomEven() {
        System.out.println("==== 自定义监听事件创建成功 ==== ");
    }
}

事件监听器

@Component
public class CustomerListener implements ApplicationListener<CustomEven> {

    @Override
    public void onEven(CustomEven customEven) {
        System.out.println("==== 发送用户登录成功邮件 ====");
    }
}

发布事件监听器

@RestController
public class DocTestController {
    @Autowired
    private ListenerHandler listenerHandler;

    @RequestMapping("/custom/login")
    public void login() {
        System.out.println("==== 用户登录成功 ====");
        System.out.println("--------------------------------");
        com.zt.study.demolistener.doc.custom.CustomEven even = new com.zt.study.demolistener.doc.custom.CustomEven();
        listenerHandler.publishEvent(even);
    }
}
  1. 基于aop使用注解实现
    为什么需要使用注解实现,在原有业务已经实现的基础上,使用上述的两种方法,都要修改原来的业务代码,修改就可能导致出现bug,使用 注解的方式的话,就不需要修改原有的代码结构,只需要在需要增加事件监听的地方增加注解即可;

监听器注解

/**
 * 自定义注解实现
 * 根据具体的情况进行选择注解范围,当前选择的是方法上
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface Listener {
    String value() default "";
}

AOP切面,切面中已经执行了事件的发布,事件源和事件监听器使用的是第一种方法中定义的。

@Component
@Aspect
public class ListenerAop {

    private CustomEven even = new CustomEven(this);

    @Autowired
    private ApplicationContext applicationContext;

    @Pointcut("@annotation(com.zt.study.demolistener.doc.anno.Listener)")
    public void listenerPoint(){}

    @Before(value = "listenerPoint()")
    public void beforeLogin(JoinPoint joinPoint) {
        System.out.println("---- 登录事件执行之前需要执行哪些  ----");
    }

    @After(value = "listenerPoint()")
    public void afterlogin() {
        System.out.println("---- 登录事件执行成功后  ----");
        // 执行监听事件
        applicationContext.publishEvent(even);
    }
}

如何使用 自定义的监听器注解

@RestController
public class DocTestController {

    @RequestMapping("/anno/login")
    @Listener(value = "登录监听事件")
    public void login() {
        System.out.println("==== 用户登录成功 ====");
        System.out.println("--------------------------------");
    }
}