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


声明:本文转载自https://my.oschina.net/silenceyawen/blog/1610900,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

接口回调

监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在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  */ @Service public 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) @SpringBootTest public 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发生之前,执行了我们在测试类中写下的监听代码,实现类监听的目的。

这就是java使用接口回调的一个例子,我在大三时也写过一篇关于回调的博客可以参考:https://my.oschina.net/silenceyawen/blog/730494

使用注解实现监听器

在以上代码中,调用 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  */ @Component public 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  */ @RestController public 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 ...

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

本文发表于2018年01月22日 12:32
(c)注:本文转载自https://my.oschina.net/silenceyawen/blog/1610900,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1525 讨论 0 喜欢 2

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1