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

网友投稿 232 2023-02-25


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

接口回调

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

实现一个监听器案例

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

1. 定义回调的接口

package com.yawn.demo.listener;

/**

* @author Created by yawn on 201uGpoHl8-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发生之前,执行了我们在测试类中写下的监听代码,实现类监听的目的。

使用注解实现监听器

在以上代码中,调用 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 uGpoHlorg.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.annotathttp://ion.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 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 getExpectListenerBeans(Class extends Annotation>... annotationTypes) {

Map listenerBeans = new LinkedHashMap<>();

for (Class extends Annotation> annotationType : annotationTypes) {

Map 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

*/

@RestControllehttp://r

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 ...

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何看懂api接口文档(api接口文档怎么看)
下一篇:忘记密码接口测试用例(密码测试用例设计)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~