在spring中使用自定义注解注册监听器的方法
接口回调
监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在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发生之前,执行了我们在测试类中写下的监听代码,实现类监听的目的。
使用注解实现监听器
在以上代码中,调用 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 ...
已经调用了监听方法。在接下来的开发中,就可以使用这个注解注册监听器了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: sql 时间函数 整理的比较全了
下一篇: SQLServe 重复行删除方法
推荐阅读
-
在spring中使用自定义注解注册监听器的方法
-
spring注解在自定义jar包中无法被扫描的解决方案
-
spring注解:@Value在使用中遇到的问题
-
在Spring 中使用@Aspect 控制自定义注解的操作
-
spring boot使用自定义注解+AOP实现对Controller层方法的日志记录
-
在Laravel5.2中,如何直接使用Auth包里的方法进行直接注册用户呢?
-
在Listener、Filter、Servlet中调用 spring 使用注解定义的bean
-
spring注解在自定义jar包中无法被扫描的解决方案
-
Java 集合框架 Arraylist的基本使用方法、Vector的特有方法、LinkedList的特有方法、在集合中删除重复自定义类型元素(重写equals方法)
-
在Spring 中使用@Aspect 控制自定义注解的操作