欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-12-01 09:47:10
接口回调 监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在java语言中,可以使用接口来实现。 实现一个监听器案例 为了方便,直接在sp...

接口回调

监听器本质上就是利用回调机制,在某个动作发生前或后,执行我们自己的一些代码。在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 ...

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。