欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在spring中使用自定義注解注冊(cè)監(jiān)聽(tīng)器的方法

 更新時(shí)間:2018年01月23日 10:45:43   作者:silenceyawen  
本篇文章主要介紹了在spring中使用自定義注解注冊(cè)監(jiān)聽(tīng)器的方法,本文就是在分析監(jiān)聽(tīng)器回調(diào)原理的基礎(chǔ)上,在spring環(huán)境中使用自定義的注解實(shí)現(xiàn)一個(gè)監(jiān)聽(tīng)器。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

接口回調(diào)

監(jiān)聽(tīng)器本質(zhì)上就是利用回調(diào)機(jī)制,在某個(gè)動(dòng)作發(fā)生前或后,執(zhí)行我們自己的一些代碼。在Java語(yǔ)言中,可以使用接口來(lái)實(shí)現(xiàn)。

實(shí)現(xiàn)一個(gè)監(jiān)聽(tīng)器案例

為了方便,直接在spring環(huán)境中定義:以工作(work)為例,定義工作開(kāi)始時(shí)(或結(jié)束時(shí))的監(jiān)聽(tīng)器。

1. 定義回調(diào)的接口

package com.yawn.demo.listener;

/**
 * @author Created by yawn on 2018-01-21 13:53
 */
public interface WorkListener {

  void onStart(String name);
}

2. 定義動(dòng)作

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();
  }
}

動(dòng)作work為一個(gè)具體的方法,在work()方法的適當(dāng)時(shí)機(jī),調(diào)用前面定義的接口。此外,在這個(gè)動(dòng)作定義類中,需要提高設(shè)置監(jiān)聽(tīng)器的方法。

3. 監(jiān)聽(tīng)測(cè)試

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoSpringAnnotationApplicationTests {

  @Resource
  private MyService myService;

  @Test
  public void test1() {
    // 接口設(shè)置監(jiān)聽(tīng)器
    myService.setWorkListener(new WorkListener() {
      @Override
      public void onStart(String name) {
        System.out.println("Start work for " + name + " !");
      }
    });
//    // lambda 表達(dá)式設(shè)置監(jiān)聽(tīng)器
//    myService.setWorkListener(name -> System.out.println("Start work for " + name + " !"));
    // 工作
    myService.work("boss");
  }

 @Test
  public void test2() {
   // 繼承實(shí)現(xiàn)類設(shè)置監(jiān)聽(tīng)器
   myService.setWorkListener(new myWorkListener());
   // 工作
   myService.work("boss");
  }

  class myWorkListener extends WorkListenerAdaptor {
    @Override
    public void onStart(String name) {
      System.out.println("Start work for " + name + " !");
    }
  }
}

使用以上兩種方法測(cè)試,得到了結(jié)果為:

Start work for boss !
working hard ...

說(shuō)明在動(dòng)作work發(fā)生之前,執(zhí)行了我們?cè)跍y(cè)試類中寫(xiě)下的監(jiān)聽(tīng)代碼,實(shí)現(xiàn)類監(jiān)聽(tīng)的目的。

使用注解實(shí)現(xiàn)監(jiān)聽(tīng)器

在以上代碼中,調(diào)用 setWorkListener(WorkListener listener)  方法一般稱作設(shè)置(注冊(cè))監(jiān)聽(tīng)器,就是將自己寫(xiě)好的監(jiān)聽(tīng)代碼,設(shè)置為動(dòng)作的監(jiān)聽(tīng)器。然而,在每次注冊(cè)監(jiān)聽(tīng)器時(shí),一般需要寫(xiě)一個(gè)類,實(shí)現(xiàn)定義好的接口或繼承實(shí)現(xiàn)接口的類,再重寫(xiě)接口定義的方法即可。因此,聰明的程序員就想簡(jiǎn)化這個(gè)過(guò)程,所以就想出了使用注解的方法。使用注解,將監(jiān)聽(tīng)代碼段寫(xiě)在一個(gè)方法中,使用一個(gè)注解標(biāo)記這個(gè)方法即可。

的確,使用變得簡(jiǎn)單了,但實(shí)現(xiàn)卻不見(jiàn)得。

1. 定義一個(gè)注解

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 需要進(jìn)行掃描的類級(jí)注解類型
   * @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;
  }
}

在注解的解析過(guò)程中,設(shè)置監(jiān)聽(tīng)器。

在解析類中,實(shí)現(xiàn)了接口ApplicationContextAware,為了在類中拿到ApplicationContext的引用,用于得到 IOC 容器中的 Bean;而實(shí)現(xiàn)接口InitializingBean,則是為了在一個(gè)合適的時(shí)機(jī)執(zhí)行解析注解、設(shè)置監(jiān)聽(tīng)器的代碼。 如果不這樣做,可以在CommandLineRunner執(zhí)行時(shí)調(diào)用解析、設(shè)置的代碼,而ApplicationContext也可以自動(dòng)注入。

3. 測(cè)試

在執(zhí)行完以上代碼后,監(jiān)聽(tīng)器就已經(jīng)設(shè)置好了,可以進(jìn)行測(cè)試了。

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 + " !");
  }
}

寫(xiě)一個(gè)監(jiān)聽(tīng)方法,參數(shù)類型和個(gè)數(shù)與接口相同,然后加上自定義的注解即可。當(dāng)啟動(dòng)環(huán)境后,監(jiān)聽(tīng)器就已經(jīng)設(shè)置好了。

然后通過(guò)url調(diào)用myService的work()方法,可以看到結(jié)果:

Start work for boss !
working hard ...

已經(jīng)調(diào)用了監(jiān)聽(tīng)方法。在接下來(lái)的開(kāi)發(fā)中,就可以使用這個(gè)注解注冊(cè)監(jiān)聽(tīng)器了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論