1

阅读spring boot如何执行事件监听器的代码,就意识到事件监听机制应该在spring boot中运用很广,而且它的代码形式就是要让开发者来使用的。所以就去搜索了下具体在Spring boot中运行事件监听器要怎么做。

因为阅读代码的过程中,spring boot内置的事件监听器已经教会我怎么在spring boot里添加事件监听器,发布事件,执行对应动作这一个流程了,所以就想看看还有没有其他的知识点。果然还是有的。

首先,一个完整的事件监听过程涉及到四个对象:
1、发送事件的主体
2、事件的类型定义
3、发布事件的发布器
4、事件的监听器

如下示例主要来自这篇《Spring Boot 事件和监听》

先来定义一个简单的事件:

package com.shahuwang.bootsample.listener;

import org.springframework.context.ApplicationEvent;

public class BlackListEvent extends ApplicationEvent {
    private String address;
    public BlackListEvent(Object source, String address){
        super(source);
        this.address = address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

再来定义一个简单的事件监听器:

package com.shahuwang.bootsample.listener;

import org.springframework.context.ApplicationListener;

public class BlackListListener implements ApplicationListener<BlackListEvent> {
    @Override
    public void onApplicationEvent(BlackListEvent blackListEvent) {
        String threaid = Thread.currentThread().getName();
        System.out.println(threaid + "收到了黑名单事件:" + blackListEvent.getAddress());
    }
}

然后把监听器注册到spring boot里面:

package com.shahuwang.bootsample;

import com.shahuwang.bootsample.listener.BlackListListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
public class BootsampleApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BootsampleApplication.class);
        app.addListeners(new BlackListListener());
        app.run(args);
    }
    
}

此时,只要在其他地方发布这个事件,马上就会执行对应的代码了。这个事件要怎么发布呢?

如下是一段简单的接口代码,在里面发布了事件:

package com.shahuwang.bootsample.service;

import com.shahuwang.bootsample.listener.BlackListEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();
    @Autowired
    private ApplicationContext context;
    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        BlackListEvent event = new BlackListEvent(this, "greeting");
        context.publishEvent(event);
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}


package com.shahuwang.bootsample.service;

public class Greeting {
    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

此时,只要把整个项目运行起来,然后访问:http://localhost:8080/greeting 就能看到console打出【收到了黑名单事件】几个字了。

如上的方式定义一个事件监听器还是复杂了点,而且需要写好多个类。Spring boot还支持某个类的方法成为监听器,如下即是:

package com.shahuwang.bootsample.listener;

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

@Component
public class AnnotationListener {
    @EventListener
    public void processBlacklistEvent(BlackListEvent event){
        String threaid = Thread.currentThread().getName();
        System.out.println("annotation listener------------------" + threaid);
    }
}

通过加上@Component 和 @EventListener 两个注解,就可以让一个方法成为监听器。

阅读代码的过程中,我看到spring boot的事件执行有两种方式,一种是在主线程里面顺序执行,一种是新起一个线程来执行,似乎是通过读取某个配置来区分。后来搜索到需要加上@Async 这个注解,然而我加上了也没有用,再后来发现还需要在主类上加上@EnableAsync这个注解。

代码如下:

package com.shahuwang.bootsample.listener;

import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

@Component
public class AnnotationListener {
    @EventListener
    @Async
    public void processBlacklistEvent(BlackListEvent event){
        String threaid = Thread.currentThread().getName();
        System.out.println("annotation listener------------------" + threaid);
    }
}
package com.shahuwang.bootsample;

import com.shahuwang.bootsample.listener.BlackListListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class BootsampleApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BootsampleApplication.class);
        app.addListeners(new BlackListListener());
        app.run(args);
    }

}

这样子每次事件到来都是新起一个线程来执行了。

除了上述两种方式注册监听器,还可以通过properties文件里面配置监听器,由spring boot在启动的时候加载。

首先,在src/resources下的application.properties(如果没有就创建一个)加上这么一行:

context.listener.classes=\
  com.shahuwang.bootsample.listener.BlackListListener

这个BackListListener 就会在启动的时候,由org.springframework.boot.context.config.DelegatingApplicationListener 加载并注册到spring boot里面了。如果有多个监听器,可以这样写:

context.listener.classes=\
  com.shahuwang.bootsample.listener.BlackListListener,\
  com.shahuwang.bootsample.listener.BlackListListener2

DelegatingApplicationListener 由spring boot初始化时启动,然后监听ApplicationEnvironmentPreparedEvent事件,收到事件后,就找当前项目的properties文件,并加载里面context.listener.classes对应的监听器


沙湖王
62 声望12 粉丝

知识需要分享才能延续生命!