2019独角兽企业重金招聘Python工程师标准>>>

接口回调

监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在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 {@Resourceprivate 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 {@Resourceprivate MyService myService;@Testpublic void test1() {// 接口设置监听器myService.setWorkListener(new WorkListener() {@Overridepublic 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");}@Testpublic void test2() {// 继承实现类设置监听器myService.setWorkListener(new myWorkListener());// 工作myService.work("boss");}class myWorkListener extends WorkListenerAdaptor {@Overridepublic 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 {@Resourceprivate MyService myService;private ApplicationContext applicationContext;@Overridepublic 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;}@Overridepublic 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 {@Resourceprivate MyService myService;@GetMapping("/work")public Object work() {myService.work("boss");return "done";}@WorkListenerpublic void listen(String name) {System.out.println("Start work for " + name + " !");}
}

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

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

Start work for boss !
working hard ...

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

转载于:https://my.oschina.net/silenceyawen/blog/1610900

在spring中使用自定义注解注册监听器相关推荐

  1. Spring中的@Value注解详解

    本文主要介绍Spring @Value 注解注入属性值的使用方法的分析,文章通过示例代码非常详细地介绍,对于每个人的学习或工作都有一定的参考学习价值 文章目录 概述 使用方式 基于配置文件的注入 基于 ...

  2. Spring中常见的注解收集

    Spring中常见的注解收集 文章目录 Spring中常见的注解收集 1.@ResponseBody 2.@RequestBody 3.@RequestParam 4.@Controller 5.@R ...

  3. Spring中利用java注解声明切面

    Spring中利用java注解声明切面 第一步:确定在Spring的XML文件中包含AOP的命名空间: 第二步:在Spring的XML文件中输入<aop:aspectj-autoproxy/&g ...

  4. Spring切面中实现自定义注解

    1.首先写出一个自定义注解. package com.salong.aspect.test;import java.lang.annotation.*;@Target(ElementType.METH ...

  5. 详细讲解Spring中的@Bean注解

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_42140261/ article/details/104864333 随着SpringBoot的流行,我们现在更 ...

  6. Spring 中的各种注解,光会用可不够哦!

    来源:https://digdeep.cnblogs.com/digdeep/p/4525567.html 1. Java中的注解 2. 使用 元注解 来自定义注解 和 处理自定义注解 3. spri ...

  7. 如何在springboot项目中使用自定义注解实现系统操作日志的功能

    通常我们的项目中都需要记录操作日志,方便回溯问题,找到根源. 因为给项目添加日志记录功能是属于系统级别的功能,所以这个问题我们马上会想到spring的AOP,可以通过切面的形式.那么怎么来实现呢? 先 ...

  8. Spring中的@ConditionalOnProperty注解

    1.概述 介绍@ConditionalOnProperty注解的主要目的. 2.@ConditionalOnProperty的目的 通常,在开发基于Spring的应用程序时,可能需要根据配置属性的存在 ...

  9. 在SpringBoot项目中,自定义注解+拦截器优雅的实现敏感数据的加解密!

    在实际生产项目中,经常需要对如身份证信息.手机号.真实姓名等的敏感数据进行加密数据库存储,但在业务代码中对敏感信息进行手动加解密则十分不优雅,甚至会存在错加密.漏加密.业务人员需要知道实际的加密规则等 ...

最新文章

  1. python中字典数据的特点_Python数据类型(字典)
  2. 关于wParam和lParam
  3. springcloud记录篇6-分布式配置中心
  4. Unity2020.1新功能探路:图形渲染相关更新
  5. Hello, Dart!
  6. 经典机器学习系列(八)【支持向量机】
  7. Leetcode 27 Remove Element
  8. 13.docker exec
  9. 密码学中的各类密码汇总(一)
  10. 搭建邮件服务器 linux,Linux局域网邮件服务器搭建
  11. 软件测试肖sir__008项目管理工具之禅道
  12. 平面设计师okr_设计团队的KPI/OKR如何制定?
  13. 原 《老路用得上的商学课》86-90学习笔记
  14. 荣耀magicbookpro升级鸿蒙,荣耀MagicBook Pro 2020到底好不好?答案就在这里
  15. 硬知识来袭,一文读懂Wi-SUN的前世今生
  16. CMD批处理实现dot命令自动运行更新
  17. 荣耀笔记本pro linux版本,荣耀MagicBook Pro锐龙版发布:首发锐龙7 3750H、还有Linux版...
  18. 投资中最简单的事--阅读笔记
  19. python中pass关键字
  20. 【Linux服务器】登录Linux服务器后,登陆信息显示佛祖保佑、永不死机,小猪佩奇等图案

热门文章

  1. hive 函数 Cube
  2. 【深入浅出jQuery】源码浅析--整体架构(转)
  3. ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程
  4. 使用CXF与Spring集成实现RESTFul WebService
  5. CDC之CreateCompatibleDC与BitBlt
  6. 个人对持续集成的理解和实践
  7. java param request_使用@RequestParam将请求参数绑定至方法参数
  8. kubernetes-Pod定义
  9. json字符串中key值下划线命名转换为驼峰命名
  10. Spring MVC 源码-运行调用阶段