首页 > 开发 > Java > 正文

在spring中使用自定义注解注册监听器的方法

2024-07-13 10:17:09
字体:
来源:转载
供稿:网友

接口回调

监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在Java语言中,可以使用接口来实现。

实现一个监听器案例

为了方便,直接在spring环境中定义:以工作(work)为例,定义工作开始时(或结束时)的监听器。

1. 定义回调的接口

package com.yawn.demo.listener;/** * @author Created by yawn on 2018-01-21 13:53 */public interface WorkListener {  void onStart(String name);}

2. 定义动作

package com.yawn.demo.service;import com.yawn.demo.listener.WorkListener;/** * @author Created by yawn on 2018-01-21 13:39 */@Servicepublic class MyService {  @Resource  private PersonService personService;  private WorkListener listener;  public void setWorkListener(WorkListener workListener) {    this.listener = workListener;  }  public void work(String name) {    listener.onStart(name);    personService.work();  }}

动作work为一个具体的方法,在work()方法的适当时机,调用前面定义的接口。此外,在这个动作定义类中,需要提高设置监听器的方法。

3. 监听测试

@RunWith(SpringRunner.class)@SpringBootTestpublic class DemoSpringAnnotationApplicationTests {  @Resource  private MyService myService;  @Test  public void test1() {    // 接口设置监听器    myService.setWorkListener(new WorkListener() {      @Override      public void onStart(String name) {        System.out.println("Start work for " + name + " !");      }    });//    // lambda 表达式设置监听器//    myService.setWorkListener(name -> System.out.println("Start work for " + name + " !"));    // 工作    myService.work("boss");  } @Test  public void test2() {   // 继承实现类设置监听器   myService.setWorkListener(new myWorkListener());   // 工作   myService.work("boss");  }  class myWorkListener extends WorkListenerAdaptor {    @Override    public void onStart(String name) {      System.out.println("Start work for " + name + " !");    }  }}

使用以上两种方法测试,得到了结果为:

Start work for boss !working hard ...

说明在动作work发生之前,执行了我们在测试类中写下的监听代码,实现类监听的目的。

使用注解实现监听器

在以上代码中,调用 setWorkListener(WorkListener listener)  方法一般称作设置(注册)监听器,就是将自己写好的监听代码,设置为动作的监听器。然而,在每次注册监听器时,一般需要写一个类,实现定义好的接口或继承实现接口的类,再重写接口定义的方法即可。因此,聪明的程序员就想简化这个过程,所以就想出了使用注解的方法。使用注解,将监听代码段写在一个方法中,使用一个注解标记这个方法即可。

的确,使用变得简单了,但实现却不见得。

1. 定义一个注解

package com.yawn.demo.anno;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface WorkListener {}

2. 解析注解

package com.yawn.demo.anno;import com.yawn.demo.service.MyService;import org.springframework.beans.BeansException;import org.springframework.beans.factory.InitializingBean;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.LinkedHashMap;import java.util.Map;/** * @author Created by yawn on 2018-01-21 14:46 */@Componentpublic class WorkListenerParser implements ApplicationContextAware, InitializingBean {  @Resource  private MyService myService;  private ApplicationContext applicationContext;  @Override  public void afterPropertiesSet() throws Exception {    Map<String, Object> listenerBeans = getExpectListenerBeans(Controller.class, RestController.class, Service.class, Component.class);    for (Object listener : listenerBeans.values()) {      for (Method method : listener.getClass().getDeclaredMethods()) {        if (!method.isAnnotationPresent(WorkListener.class)) {          continue;        }        myService.setWorkListener(name -> {          try {            method.invoke(listener, name);          } catch (Exception e) {            e.printStackTrace();          }        });      }    }  }  /**   * 找到有可能使用注解的bean   * @param annotationTypes 需要进行扫描的类级注解类型   * @return 扫描到的beans的map   */  private Map<String, Object> getExpectListenerBeans(Class<? extends Annotation>... annotationTypes) {    Map<String, Object> listenerBeans = new LinkedHashMap<>();    for (Class<? extends Annotation> annotationType : annotationTypes) {      Map<String, Object> annotatedBeansMap = applicationContext.getBeansWithAnnotation(annotationType);      listenerBeans.putAll(annotatedBeansMap);    }    return listenerBeans;  }  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {    this.applicationContext = applicationContext;  }}

在注解的解析过程中,设置监听器。

在解析类中,实现了接口ApplicationContextAware,为了在类中拿到ApplicationContext的引用,用于得到 IOC 容器中的 Bean;而实现接口InitializingBean,则是为了在一个合适的时机执行解析注解、设置监听器的代码。 如果不这样做,可以在CommandLineRunner执行时调用解析、设置的代码,而ApplicationContext也可以自动注入。

3. 测试

在执行完以上代码后,监听器就已经设置好了,可以进行测试了。

package com.yawn.demo.controller;import com.yawn.demo.anno.WorkListener;import com.yawn.demo.service.MyService;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/** * @author Created by yawn on 2018-01-21 13:28 */@RestControllerpublic class TestController {  @Resource  private MyService myService;  @GetMapping("/work")  public Object work() {    myService.work("boss");    return "done";  }  @WorkListener  public void listen(String name) {    System.out.println("Start work for " + name + " !");  }}

写一个监听方法,参数类型和个数与接口相同,然后加上自定义的注解即可。当启动环境后,监听器就已经设置好了。

然后通过url调用myService的work()方法,可以看到结果:

Start work for boss !working hard ...

已经调用了监听方法。在接下来的开发中,就可以使用这个注解注册监听器了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表