在spring中使用自定义注解注册监听器的方法
接口回调
监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在Java语言中,可以使用接口来实现。
实现一个监听器案例
为了方便,直接在spring环境中定义:以工作(work)为例,定义工作开始时(或结束时)的监听器。
1.定义回调的接口
packagecom.yawn.demo.listener; /** *@authorCreatedbyyawnon2018-01-2113:53 */ publicinterfaceWorkListener{ voidonStart(Stringname); }
2.定义动作
packagecom.yawn.demo.service; importcom.yawn.demo.listener.WorkListener; /** *@authorCreatedbyyawnon2018-01-2113:39 */ @Service publicclassMyService{ @Resource privatePersonServicepersonService; privateWorkListenerlistener; publicvoidsetWorkListener(WorkListenerworkListener){ this.listener=workListener; } publicvoidwork(Stringname){ listener.onStart(name); personService.work(); } }
动作work为一个具体的方法,在work()方法的适当时机,调用前面定义的接口。此外,在这个动作定义类中,需要提高设置监听器的方法。
3.监听测试
@RunWith(SpringRunner.class) @SpringBootTest publicclassDemoSpringAnnotationApplicationTests{ @Resource privateMyServicemyService; @Test publicvoidtest1(){ //接口设置监听器 myService.setWorkListener(newWorkListener(){ @Override publicvoidonStart(Stringname){ System.out.println("Startworkfor"+name+"!"); } }); ////lambda表达式设置监听器 //myService.setWorkListener(name->System.out.println("Startworkfor"+name+"!")); //工作 myService.work("boss"); } @Test publicvoidtest2(){ //继承实现类设置监听器 myService.setWorkListener(newmyWorkListener()); //工作 myService.work("boss"); } classmyWorkListenerextendsWorkListenerAdaptor{ @Override publicvoidonStart(Stringname){ System.out.println("Startworkfor"+name+"!"); } } }
使用以上两种方法测试,得到了结果为:
Startworkforboss! workinghard...
说明在动作work发生之前,执行了我们在测试类中写下的监听代码,实现类监听的目的。
使用注解实现监听器
在以上代码中,调用setWorkListener(WorkListenerlistener) 方法一般称作设置(注册)监听器,就是将自己写好的监听代码,设置为动作的监听器。然而,在每次注册监听器时,一般需要写一个类,实现定义好的接口或继承实现接口的类,再重写接口定义的方法即可。因此,聪明的程序员就想简化这个过程,所以就想出了使用注解的方法。使用注解,将监听代码段写在一个方法中,使用一个注解标记这个方法即可。
的确,使用变得简单了,但实现却不见得。
1.定义一个注解
packagecom.yawn.demo.anno; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public@interfaceWorkListener{ }
2.解析注解
packagecom.yawn.demo.anno; importcom.yawn.demo.service.MyService; importorg.springframework.beans.BeansException; importorg.springframework.beans.factory.InitializingBean; importorg.springframework.context.ApplicationContext; importorg.springframework.context.ApplicationContextAware; importorg.springframework.stereotype.Component; importjavax.annotation.Resource; importjava.lang.annotation.Annotation; importjava.lang.reflect.Method; importjava.util.LinkedHashMap; importjava.util.Map; /** *@authorCreatedbyyawnon2018-01-2114:46 */ @Component publicclassWorkListenerParserimplementsApplicationContextAware,InitializingBean{ @Resource privateMyServicemyService; privateApplicationContextapplicationContext; @Override publicvoidafterPropertiesSet()throwsException{ MaplistenerBeans=getExpectListenerBeans(Controller.class,RestController.class,Service.class,Component.class); for(Objectlistener:listenerBeans.values()){ for(Methodmethod:listener.getClass().getDeclaredMethods()){ if(!method.isAnnotationPresent(WorkListener.class)){ continue; } myService.setWorkListener(name->{ try{ method.invoke(listener,name); }catch(Exceptione){ e.printStackTrace(); } }); } } } /** *找到有可能使用注解的bean *@paramannotationTypes需要进行扫描的类级注解类型 *@return扫描到的beans的map */ privateMap getExpectListenerBeans(Class...annotationTypes){ Map listenerBeans=newLinkedHashMap<>(); for(ClassannotationType:annotationTypes){ Map annotatedBeansMap=applicationContext.getBeansWithAnnotation(annotationType); listenerBeans.putAll(annotatedBeansMap); } returnlistenerBeans; } @Override publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{ this.applicationContext=applicationContext; } }
在注解的解析过程中,设置监听器。
在解析类中,实现了接口ApplicationContextAware,为了在类中拿到ApplicationContext的引用,用于得到IOC容器中的Bean;而实现接口InitializingBean,则是为了在一个合适的时机执行解析注解、设置监听器的代码。如果不这样做,可以在CommandLineRunner执行时调用解析、设置的代码,而ApplicationContext也可以自动注入。
3.测试
在执行完以上代码后,监听器就已经设置好了,可以进行测试了。
packagecom.yawn.demo.controller; importcom.yawn.demo.anno.WorkListener; importcom.yawn.demo.service.MyService; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.RestController; importjavax.annotation.Resource; /** *@authorCreatedbyyawnon2018-01-2113:28 */ @RestController publicclassTestController{ @Resource privateMyServicemyService; @GetMapping("/work") publicObjectwork(){ myService.work("boss"); return"done"; } @WorkListener publicvoidlisten(Stringname){ System.out.println("Startworkfor"+name+"!"); } }
写一个监听方法,参数类型和个数与接口相同,然后加上自定义的注解即可。当启动环境后,监听器就已经设置好了。
然后通过url调用myService的work()方法,可以看到结果:
Startworkforboss! workinghard...
已经调用了监听方法。在接下来的开发中,就可以使用这个注解注册监听器了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。