Spring Lifecycle的使用

前言

小杰在前面的文章讲过可以使用 @PostConstructInitializingBean xml init@PreDestroyDisposableBean xml destroy来处理 Bean 的初始化和销毁,上述这些操作是属于 Bean 生命周期的。

那如果我想在容器本身的生命周期(比如容器启动、停止)上做一些工作怎么办呢?Spring 提供了以下接口。

Lifecycle

定义启动/停止生命周期方法的通用接口。

public interface Lifecycle {
    /**
     * 容器启动后调用
     */
	void start();
    /**
     * 容器停止时调用
     */
	void stop();

   /**
     * 检查此组件是否正在运行。
     * 1. 只有该方法返回false时,start方法才会被执行。
     * 2. 只有该方法返回true时,stop()方法才会被执行。
     */
	boolean isRunning();
}

自定义Lifecycle实现类

@Component
public class CustomizeLifecycle implements Lifecycle {
	private volatile boolean running = false;
	@Override
	public void start() {
		running = true;
		System.out.println("start ==== ");
	}
	@Override
	public void stop() {
		running = false;
		System.out.println("stop ==== ");
	}
	@Override
	public boolean isRunning() {
		return running;
	}
}

测试

@ComponentScan(basePackages = {"com.gongj.lifecycle"})
public class AppApplication {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context =
				new AnnotationConfigApplicationContext(AppApplication.class);
		context.start();
		context.stop();
	}
}
结果:
isRunning ====> false
start ====>
isRunning ====> true
stop ====>

使用 Lifecycle这种方式,需要显示的调用容器的 startstop方法。 显得笨重,所以我们使用另外一种方式 :SmartLifecycle

SmartLifecycle

public interface SmartLifecycle extends Lifecycle, Phased {
	int DEFAULT_PHASE = Integer.MAX_VALUE;
	default boolean isAutoStartup() {
		return true;
	}
	default void stop(Runnable callback) {
		stop();
		callback.run();
	}
	@Override
	default int getPhase() {
		return DEFAULT_PHASE;
	}
}

看到的源码定义,SmartLifecycle除了继承Lifecycle之外,还继承了 Phased。并且新增了几个方法:

  • isAutoStartup:是否自动启动。为 treu,则自动调用start();为 false,则需要显示调用 start()
  • stop:当 isRunning 方法返回 true 时,该方法才会被调用。
  • getPhase:来自于 Phased 接口,当容器中有多个实现了 SmartLifecycle的类,这个时候可以依据 getPhase方法返回值来决定start 方法、 stop方法的执行顺序。 start 方法执行顺序按照 getPhase方法返回值从小到大执行,而 stop方法则相反。比如: 启动时:1 比 3 先执行,-1 比 1 先执行,退出时:3 比 1 先退出,1 比 -1 先退出。

自定义SmartLifecycle实现类

@Component
public class CustomizeSmartLifecycle implements SmartLifecycle {
	private volatile boolean running = false;
	@Override
	public void start() {
		running = true;
		System.out.println("CustomizeSmartLifecycle start()");
	}
	@Override
	public void stop() {
		System.out.println("CustomizeSmartLifecycle stop()");
		running = false;
	}
	@Override
	public boolean isRunning() {
		System.out.println("CustomizeSmartLifecycle isRunning() ==== " + running);
		return running;
	}
	@Override
	public boolean isAutoStartup() {
		return true;
	}
	@Override
	public void stop(Runnable callback) {
		System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
		callback.run();
	}
	@Override
	public int getPhase() {
		return 1;
	}
}

将代码进行启动,控制台打印如下内容:

public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
        new AnnotationConfigApplicationContext(AppApplication.class);
    //context.start();
    //context.stop();
}
结果:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()

发现并没有执行 stop方法,这是因为容器问题。如果在Spring Boot项目会自动执行的,小伙伴可以试一试。

在本例中,还是需要显示调用 stop方法。

public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
        new AnnotationConfigApplicationContext(AppApplication.class);
    //context.start();
    context.stop();
}
结果:
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)

发现执行了stop(Runnable callback),并没有执行 stop方法。这是因为当前类是 SmartLifecycle的子类,如果要执行 stop方法,需要在stop(Runnable callback)显示调用。

@Override
public void stop(Runnable callback) {
    System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
    stop();
    callback.run();
}
或者
@Override
public void stop(Runnable callback) {
    SmartLifecycle.super.stop(callback);
}

启动结果如下:

CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle stop()

注意:在stop(Runnable callback)方法中不要忘记调用 callback.run()方法。否则DefaultLifecycleProcessor会认为这个SmartLifecycle没有stop完成,程序会等待一定时间,默认30秒后才会自动结束。

@Override
public void stop(Runnable callback) {
    System.out.println("CustomizeSmartLifecycle stop(Runnable callback)");
    //stop();
    //callback.run();
}

多个实现类

@Component
public class CustomizeSmartLifecycle2 implements SmartLifecycle {
	private volatile boolean running = false;
	@Override
	public void start() {
		running = true;
		System.out.println("CustomizeSmartLifecycle2 start() =====>");
	}
	@Override
	public void stop() {
		System.out.println("CustomizeSmartLifecycle1 stop() =====>");
		running = false;
	}
	@Override
	public boolean isRunning() {
		System.out.println("CustomizeSmartLifecycle2 isRunning() =====> " + running);
		return running;
	}
	@Override
	public boolean isAutoStartup() {
		return true;
	}
	@Override
	public void stop(Runnable callback) {
		System.out.println("CustomizeSmartLifecycle2 stop(Runnable callback) =====>");
		callback.run();
	}
	@Override
	public int getPhase() {
		return -1;
	}
}

getPhase方法返回 -1。按照前面所说的结论,那就是 CustomizeSmartLifecycle2start方法会先执行,然后 CustomizeSmartLifecycle2stop方法最后执行。我们一起来看看执行结果吧!

public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
        new AnnotationConfigApplicationContext(AppApplication.class);
    //context.start();
    context.stop();
}

执行结果:

CustomizeSmartLifecycle2 isRunning() =====> false
CustomizeSmartLifecycle2 start() =====>
CustomizeSmartLifecycle isRunning() ==== false
CustomizeSmartLifecycle start()
CustomizeSmartLifecycle isRunning() ==== true
CustomizeSmartLifecycle stop(Runnable callback)
CustomizeSmartLifecycle2 isRunning() =====> true
CustomizeSmartLifecycle2 stop(Runnable callback) =====>

跟结论保持一致。

源码分析

基本的使用就到此结束啦!我们来结合源码分析分析吧!

我们来到 finishRefresh方法的 getLifecycleProcessor().onRefresh();方法。

protected void finishRefresh() {
    // Clear context-level resource caches (such as ASM metadata from scanning).
    clearResourceCaches();
    // Initialize lifecycle processor for this context.
    //为此上下文初始化生命周期处理器
    initLifecycleProcessor();
    // Propagate refresh to lifecycle processor first.
    // 默认调用 DefaultLifecycleProcessor 的 onRefresh 方法
    // 找出 Lifecycle Bean 执行 start 方法,默认情况下是没有Lifecycle Bean的,需要自己定义
    getLifecycleProcessor().onRefresh();
    // Publish the final event.
    // 发布事件  ContextRefreshedEvent 是一个事件
    publishEvent(new ContextRefreshedEvent(this));
    // Participate in LiveBeansView MBean, if active.
    LiveBeansView.registerApplicationContext(this);
}

getLifecycleProcessor()方法获得容器中的 LifecycleProcessor对象,默认就是 DefaultLifecycleProcessor

LifecycleProcessor

public interface LifecycleProcessor extends Lifecycle {
	/**
	 * Notification of context refresh, e.g. for auto-starting components.
	 * 上下文刷新的通知,例如 用于自动启动组件
	 */
	void onRefresh();
	/**
	 * Notification of context close phase, e.g. for auto-stopping components.
	 * 上下文关闭的通知,例如 用于自动停止组件。
	 */
	void onClose();
}

接口中就定义的两个方法。onRefreshonClose

onRefresh

我们先来看一下 onRefresh方法的内部逻辑,分析它是如何自动调用 start方法的。

@Override
public void onRefresh() {
    startBeans(true);
    this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
    // 获取所有的Lifecycle Bean
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    // 将Lifecycle Bean 按阶段分组,阶段通过实现 Phased 接口得到
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    // 遍历所有Lifecycle Bean 按阶段值进行分组
    lifecycleBeans.forEach((beanName, bean) -> {
        // 当autoStartupOnly=false,显示调用 start()方法进行启动,会触发全部的Lifecycle;
        // 当autoStartupOnly=true,调用容器的 refresh 方法启动,只会触发isAutoStartup方法返回true的SmartLifecycle
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            int phase = getPhase(bean);
            LifecycleGroup group = phases.get(phase);
            if (group == null) {
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }
            group.add(beanName, bean);
        }
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        Collections.sort(keys);
        for (Integer key : keys) {
            // 调用 Lifecycle 的 start 方法
            phases.get(key).start();
        }
    }
}

这里注意一下 autoStartupOnly的值为 true

  • autoStartupOnly=true,调用容器的 refresh 方法,由容器调用 onRefresh方法自动启动,只会触发 isAutoStartup方法返回 trueSmartLifecycle。而 isAutoStartup属性,小杰在分析SmartLifecycle的时候已经讲过。
  • autoStartupOnly=false,显示调用 start()方法进行启动,会触发全部的Lifecycle
@Override
public void start() {
    getLifecycleProcessor().start();
    publishEvent(new ContextStartedEvent(this));
}
//传入 false
@Override
public void start() {
    startBeans(false);
    this.running = true;
}

onClose

onClose在我没有找到调用点,但是 onClose内部会调用stopBeans()方法。我们直接分析stopBeans方法。

stopBeans方法跟 startBeans的逻辑大体差不多,然后调用 stop方法。

@Override
public void onClose() {
    stopBeans();
    this.running = false;
}
private void stopBeans() {
    // 获取所有的Lifecycle Bean
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    lifecycleBeans.forEach((beanName, bean) -> {
        // 获得 phase 的值
        int shutdownPhase = getPhase(bean);
        LifecycleGroup group = phases.get(shutdownPhase);
        // 按阶段值进行分组
        if (group == null) {
            // this.timeoutPerShutdownPhase 就是等待时间
            group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false);
            phases.put(shutdownPhase, group);
        }
        group.add(beanName, bean);
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        keys.sort(Collections.reverseOrder());
        for (Integer key : keys) {
            //调用 stop 方法
            phases.get(key).stop();
        }
    }
}

stop

创建一个 CountDownLatch对象,如果 count不为 0 ,则线程进行等待,默认等待 30 s。

public void stop() {
  if(this.members.isEmpty()) {
    return;
  }
  if(logger.isDebugEnabled()) {
    logger.debug("Stopping beans in phase " + this.phase);
  }
  this.members.sort(Collections.reverseOrder());
  // 创建 CountDownLatch 对象 ,count 为 smartMemberCount
  // smartMemberCount 为 SmartLifecycle Bean的个数
  CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
  Set < String > countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet < > ());
  Set < String > lifecycleBeanNames = new HashSet < > (this.lifecycleBeans.keySet());
  for(LifecycleGroupMember member: this.members) {
    if(lifecycleBeanNames.contains(member.name)) {
      //调用 dostop 方法
      doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
    } else if(member.bean instanceof SmartLifecycle) {
      // Already removed: must have been a dependent bean from another phase
      //将count值减1
      latch.countDown();
    }
  }
  try {
    //调用 await() 方法的线程会被挂起,等待一定的时间后,如果 count值还没有为 0 才继续执行
    latch.await(this.timeout, TimeUnit.MILLISECONDS);
    if(latch.getCount() > 0 && !countDownBeanNames.isEmpty() && logger.isInfoEnabled()) {
      logger.info("Failed to shut down " + countDownBeanNames.size() + " bean" + (countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " + this.phase + " within timeout of " + this.timeout + ": " + countDownBeanNames);
    }
  } catch(InterruptedException ex) {
    Thread.currentThread().interrupt();
  }
}
}

doStop

doStop 方法的逻辑很简单。区分是否是SmartLifecycle类型,如果是执行stop(Runnable callback)方法,反之执行 stop()方法。

private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName,
                    final CountDownLatch latch, final Set<String> countDownBeanNames) {
    Lifecycle bean = lifecycleBeans.remove(beanName);
    if (bean != null) {
        String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
        for (String dependentBean : dependentBeans) {
            doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames);
        }
        try {
            // 判断 isRunning 的值
            if (bean.isRunning()) {
                // 如果是 SmartLifecycle 类型,则执行 stop(Runnable callback) 方法
                if (bean instanceof SmartLifecycle) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Asking bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "] to stop");
                    }
                    countDownBeanNames.add(beanName);
                    // 这里就是为什么要调用 callback.run() 的原因
                    // 传入的是一个 lambad 表达式,所以需要调用callback.run(),才会执行 lambad 体
                    // 在lambad 体才会执行 latch.countDown()
                    ((SmartLifecycle) bean).stop(() -> {
                        //将count值减1
                        latch.countDown();
                        countDownBeanNames.remove(beanName);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Bean '" + beanName + "' completed its stop procedure");
                        }
                    });
                }
                else {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Stopping bean '" + beanName + "' of type [" +
                                     bean.getClass().getName() + "]");
                    }
                    // 否则执行 stop() 方法
                    bean.stop();
                    if (logger.isDebugEnabled()) {
                        logger.debug("Successfully stopped bean '" + beanName + "'");
                    }
                }
            }
            else if (bean instanceof SmartLifecycle) {
                // Don't wait for beans that aren't running...
                latch.countDown();
            }
        }
        catch (Throwable ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Failed to stop bean '" + beanName + "'", ex);
            }
        }
    }
}

关于Lifecycle的使用与源码分析就到这啦!

到此这篇关于Spring Lifecycle的使用的文章就介绍到这了,更多相关Spring Lifecycle使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Lifecycle的使用

    前言 小杰在前面的文章讲过可以使用 @PostConstruct.InitializingBean .xml init. @PreDestroy .DisposableBean .xml destroy来处理 Bean 的初始化和销毁,上述这些操作是属于 Bean 生命周期的. 那如果我想在容器本身的生命周期(比如容器启动.停止)上做一些工作怎么办呢?Spring 提供了以下接口. Lifecycle 定义启动/停止生命周期方法的通用接口. public interface Lifecycle

  • Spring Bean初始化及销毁多种实现方式

    这篇文章主要介绍了Spring Bean初始化及销毁多种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.前言 日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源.Spring 框架提供相关功能,围绕 Spring Bean 生命周期,可以在 Bean 创建过程初始化资源,以及销毁 Bean 过程释放资源.Spring 提供多种不同的方式初始化/销毁 Bean,如果同时使用这几种方式,Spring 如何处理这几

  • 浅谈如何优雅地停止Spring Boot应用

    首先来介绍下什么是优雅地停止,简而言之,就是对应用进程发送停止指令之后,能保证 正在执行的业务操作不受影响,可以继续完成已有请求的处理,但是停止接受新请求 . 在 Spring Boot 2.3 中增加了新特性 优雅停止 ,目前 Spring Boot 内置的四个嵌入式 Web 服务器( Jetty.Reactor Netty.Tomcat 和 Undertow )以及反应式和基于 Servlet 的 Web 应用程序都支持优雅停止. 下面,我们先用新版本尝试下: Spring Boot 2.3

  • 详解Spring Boot最新版优雅停机的方法

    什么是优雅停机 先来一段简单的代码,如下: @RestController public class DemoController { @GetMapping("/demo") public String demo() throws InterruptedException { // 模拟业务耗时处理流程 Thread.sleep(20 * 1000L); return "hello"; } } 当我们流量请求到此接口执行业务逻辑的时候,若服务端此时执行关机 (ki

  • spring初始化方法的执行顺序及其原理分析

    目录 Spring中初始化方法的执行顺序 首先通过一个例子来看其顺序 配置 我们进入这个类看 我们看到了annotation-config了 我们重点看下这行代码 我们直接看initializeBean这个方法 spring加载顺序典例 解决方案 Spring中初始化方法的执行顺序 首先通过一个例子来看其顺序 /**  * 调用顺序 init2(PostConstruct注解) --> afterPropertiesSet(InitializingBean接口) --> init3(init-

  • Spring Boot优化后启动速度快到飞起技巧示例

    目录 引言 启动时间分析 启动优化 减少业务初始化 延迟初始化 Spring Context Indexer 关闭JMX 关闭分层编译 另外的思路 JAR Index APPCDS Heap Archive AOT编译 下线时间优化 优雅下线 Eureka服务下线时间 结束 引言 微服务用到一时爽,没用好就呵呵啦,特别是对于服务拆分没有把控好业务边界.拆分粒度过大等问题,某些 Spring Boot 启动速度太慢了,可能你也会有这种体验,这里将探索一下关于 Spring Boot 启动速度优化的

  • Spring中SmartLifecycle和Lifecycle的作用和区别

    本文基于SpringBoot 2.5.0-M2讲解Spring中Lifecycle和SmartLifecycle的作用和区别,以及如何控制SmartLifecycle的优先级. 并讲解SpringBoot中如何通过SmartLifecycle来启动/停止web容器. SmartLifecycle和Lifecycle作用 都是让开发者可以在所有的bean都创建完成(getBean) 之后执行自己的初始化工作,或者在退出时执行资源销毁工作. SmartLifecycle和Lifecycle区别 1.

  • Apache shiro的简单介绍与使用教程(与spring整合使用)

    apache shiro框架简介 Apache Shiro是一个强大而灵活的开源安全框架,它能够干净利落地处理身份认证,授权,企业会话管理和加密.现在,使用Apache Shiro的人越来越多,因为它相当简单,相比比Spring Security,Shiro可能没有Spring Security那么多强大的功能,但是在实际工作时可能并不需要那么复杂的东西,所以使用简单的Shiro就足够了. 以下是你可以用 Apache Shiro所做的事情: Shiro的4大核心部分--身份验证,授权,会话管理

  • Spring Boot启动过程(六)之内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动教程详解

    StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程中,它的start: // Start our child containers, if any Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < childre

  • Spring Boot启动过程完全解析(二)

    上篇给大家介绍了Spring Boot启动过程完全解析(一),大家可以点击参考下 该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractApplicationContext类型并调用它的refresh方法.由于AnnotationConfigEmbeddedWebApplicationContext继承自EmbeddedWebApplicationContext,所以会

随机推荐