SmartLifecycle -- Spring提供的一个妙用

256 阅读2分钟

SmartLifecycle基本介绍

最近在写一个新项目,这个项目需要用到redis stream作为消息队列,我们平时用的Rocketmq跟Rabbitmq都有对应的Spring-boot-starter,直接引入再使用对应监听注解就可以了,然而redis stream作为消息队列,我们就需要自己造了。

所谓自动监听,其实就是当我们服务启动后,自动跟中间件产生链接,那这个自动,肯定不是我们起一个定时任务还是什么,这时候我们如果是Spring框架的服务,就可以用到Spring里的SmartLifecycle。

public interface SmartLifecycle extends Lifecycle, Phased {
    int DEFAULT_PHASE = 2147483647;

    default boolean isAutoStartup() {
        return true;
    }

    default void stop(Runnable callback) {
        this.stop();
        callback.run();
    }

    default int getPhase() {
        return 2147483647;
    }
}

public interface Lifecycle {
    void start();

    void stop();

    boolean isRunning();
}

在我们Spring容器全部完成装载后,它就会调用我们Lifecycle对应实现类,当然我们看到它里面有个stop方法,也是在我们Spring容器进行关闭的时候,我们也可以实现一些我们需要关闭的需求。

SmartLifecycle 案例实现

对应我这个设置监听注解的实现

@Component
public class MqMessageListenerContext implements SmartLifecycle, ApplicationContextAware {

    private volatile boolean running = false;

    private ApplicationContext applicationContext;

    @Override
    public void start() {
        if (!running) {
            Map<String, MqMessageListenerHandler> beansOfType = applicationContext.getBeansOfType(MqMessageListenerHandler.class);
            if (beansOfType != null && beansOfType.size() != 0) {
                    for (String beanType : beansOfType.keySet()) {
                        MqMessageListenerHandler listenerHandler = beansOfType.get(beanType);
                        //获取类上的MqMessageListener注解
                        MqMessageListener annotation = AopUtils.getTargetClass(listenerHandler)
                                .getAnnotation(MqMessageListener.class);
                        if (annotation == null) {
                            continue;
                        }
                        //内层实现直接起个子线程内部循环获取stream数据
                        startListen(annotation, listenerHandler);
                    }
            }
        }
    }

    @Override
    public void stop() {
        this.running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }

注解的使用:

image.png

对应在Spring容器启动后,我的实现是从applicationContext中拿出我所需要的消费者对应bean,这里为什么不直接用@Autowrite注入呢,因为不是每个服务都会有消费者,需要留意这一点,不然就会出现启动异常。