当前位置: 移动技术网 > IT编程>开发语言>Java > 在spring中使用自定义注解注册监听器的方法

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

2019年07月19日  | 移动技术网IT编程  | 我要评论

童伙,索爱t55,成人电视台

接口回调

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

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

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网