返回顶部
首页 > 资讯 > 后端开发 > Python >Spring Lifecycle的使用小结
  • 950
分享到

Spring Lifecycle的使用小结

2024-04-02 19:04:59 950人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言Lifecycle自定义Lifecycle实现类测试SmartLifecycle自定义SmartLifecycle实现类多个实现类源码分析LifecycleProcessor

前言

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

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

Lifecycle

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

public interface Lifecycle {
    
	void start();
    
	void 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();
}

image-20220108151717136

多个实现类

@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 {
	
	void onRefresh();
	
	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使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring Lifecycle的使用小结

本文链接: https://lsjlt.com/news/148104.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring Lifecycle的使用小结
    目录前言Lifecycle自定义Lifecycle实现类测试SmartLifecycle自定义SmartLifecycle实现类多个实现类源码分析LifecycleProcessor...
    99+
    2024-04-02
  • Spring中的Lifecycle接口使用与源码分析
    目录Lifecycle接口的声明Lifecycle的使用SmartLifecycle接口的声明SmartLifecycle的使用源码解读Lifecycle的调用时机SmartLife...
    99+
    2023-05-20
    Spring 接口 Spring Lifecycle
  • Spring项目XML文件使用小结
    目录1 项目pom.xml2 项目初始IOC容器3 项目需要自动装配4 项目需要注解1 项目pom.xml <xml version="1.0" encoding="UTF-8...
    99+
    2024-04-02
  • Spring中字段格式化的使用小结
    目录1、Formatter SPI2、基于注解的格式化3、FormatterRegistry4、SpringMVC中配置类型转换Spring提供的一个core.convert包&nb...
    99+
    2024-04-02
  • Spring Security中使用authorizeRequests遇到的问题小结
    目录SpringSecurity 框架简介 一、运行项目报错 二、错误修正SpringSecurity 框架简介 Spring 是非常流行和成功的 Java 应用开发框架,Sprin...
    99+
    2023-02-03
    Spring Security使用authorizeRequests Spring Security遇到问题
  • SpringCloud-Spring Boot Starter使用测试及问题小结
    目录Spring Boot Starter是什么?以前传统的做法使用 Spring Boot Starter 之后starter 的理念:starter 的实现:创建Spring B...
    99+
    2024-04-02
  • np.ones的使用小结
    目录概述用法例子概述 np.ones()函数返回给定形状和数据类型的新数组,其中元素的值设置为1。此函数与numpy zeros()函数非常相似。 用法 np.ones(shape,...
    99+
    2023-03-14
    np.ones 使用 np.ones
  • Android Jetpack组件Lifecycle怎么使用
    本文小编为大家详细介绍“Android Jetpack组件Lifecycle怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android Jetpack组件Lifecycle怎么使用”文章能帮助大家解决疑惑,下...
    99+
    2023-07-05
  • 基于Spring的注解@Qualifier小结
    目录Spring的注解@Qualifier小结先说明下场景,代码如下@qualifier注解参见下面的例子Spring的注解@Qualifier小结 近期在捯饬spring的注解,现...
    99+
    2024-04-02
  • Bash EOF的使用小结
    目录1. 命令行输出2. 写入文本3. 追加文本4. 覆盖文本5. 自定义 EOF6. 另一种格式7. 示例7.1 配置文件7.2 新建分区并挂载7.3 设置变量7.4 输出脚本7.5 匹配输出7.6 json 文本参考...
    99+
    2023-01-12
    Bash EOF
  • Bash EOF的使用小结
    目录1. 命令行输出2. 写入文本3. 追加文本4. 覆盖文本5. 自定义 EOF6. 另一种格式7. 示例7.1 配置文件7.2 新建分区并挂载7.3 设置变量7.4 输出脚本7....
    99+
    2023-01-12
    Bash EOF
  • document.cookie使用小结
    目录一、cookie设置二、修改cookie值三、获取cookie值四、删除cookie值一、cookie设置 1、每个cookie都是键/值对,设置多个时,用;隔开,如:docum...
    99+
    2024-04-02
  • document.cookie 使用小结
    document.cookie 是一个用于读取和设置浏览器 cookie 的属性。使用 document.cookie,可以实现以下操作:1. 读取 cookie:可以通过访问 document.cookie 来读取当前页面的所有 co...
    99+
    2023-08-11
    document.cookie
  • android lifecycle的用法是什么
    Android生命周期是指一个Android应用程序在从启动到结束的整个过程中所经历的状态变化。Android框架提供了一系列的方法...
    99+
    2023-10-18
    android
  • SpringBoot中Dozer的使用小结
    什么是Dozer? Dozer是一种Java Bean到Java Bean的映射器,递归地将数据从一个对象复制到另一个对象,它是一个强大的,通用的,灵活的,可重用的和可配置的开源映射...
    99+
    2024-04-02
  • jsoup 框架的使用小结
    目录概述概念简介相关概念简介jsoup 的主要类APIJsoup 类Connection 接口Element(元素)类查找元素获取元素数据修改数据基本使用获取文档(Document)...
    99+
    2023-05-14
    jsoup使用 jsoup 框架用法
  • Spring Cloud Sleuth 和 Zipkin 进行分布式跟踪使用小结
    目录什么是分布式跟踪?分布式跟踪的关键概念带有SpringCloudSleuth的SpringBoot示例使用Zipkin可视化跟踪分布式跟踪允许您跟踪分布式系统中的请求。本文通过了...
    99+
    2024-04-02
  • ORACLE ANALYZE使用小结
      ANALYZE的介绍       使用ANALYZE可以收集或删除对象的统计信息、验证对象的结构、标识表或cluster中的行迁移/行链接信息等。官方文档关于ANALYZE功能介绍如下:   ·         Collect...
    99+
    2017-07-04
    ORACLE ANALYZE使用小结
  • Android Webview使用小结
    本文实例为大家分享了Android Webview使用小结,供大家参考,具体内容如下 #采用重载URL的方式实现Java与Js交互 在Android中,常用的Java与Js交互...
    99+
    2022-06-06
    小结 webview Android
  • Android实用小技巧之利用Lifecycle写出更好维护的代码
    目录前言场景优化版本1优化版本2单元测试总结前言 你是否在onStart()启动过某项任务却忘记在onStop()中取消呢?人不是机器,难免会有错漏。就算老手不会犯错,也不能保...
    99+
    2022-06-07
    技巧 Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作