Spring Bean 的生命周期详解
所谓万物皆对象,对于一个 bean 而言,从出生到死亡,他要经历哪些阶段呢?
生命周期
理解对象的生命周期,可以帮助我们更好的做一些扩展。

一个对象从被创建到被垃圾回收,可以大致分为这 5 个阶段:
- 创建/实例化阶段:调用类的构造方法,产生一个新对象;
- 初始化阶段:此时对象已经被创建了,但还未被正常使用,可以在这里做一些初始化的操作;
- 运行使用期:此时对象已经完全初始化好,程序正常运行,对象被使用;
- 销毁阶段:此时对象准备被销毁,需要预先的把自身占用的资源等处理好(如关闭、释放数据库连接);
- 回收阶段:此时对象已经完全没有被引用了,被垃圾回收器回收。
理解了一个 Bean 的生命周期后,下面我们看下SpringFramework怎么对Bean 的生命周期做干预的。
单实例 Bean 的生命周期
init-method & destroy-method
1)创建 Bean
package com.study.spring.a_initmethod;public class Cat {private String name;public Cat() {System.out.println("Cat 构造方法执行了。。。");}public void setName(String name) {System.out.println("setName方法执行了。。。");this.name = name;}public void init() {System.out.println(name + " 被初始化了。。。");}public void destroy() {System.out.println(name + " 被销毁了。。。");}
}public class Dog {private String name;public Dog() {System.out.println("Dog 构造方法执行了。。。");}public void setName(String name) {System.out.println("setName方法执行了。。。");this.name = name;}public void init() {System.out.println(name + "被初始化了。。。");}public void destroy() {System.out.println(name + "被销毁了。。。");}
}
2)分别创建 XML 文件 和 注解配置类
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.study.spring.a_initmethod.Cat" init-method="init" destroy-method="destroy"><property name="name" value="小米米"/></bean>
</beans>
@Configuration
public class Config {@Bean(initMethod = "init",destroyMethod = "destroy")public Dog dog(){Dog dog = new Dog();dog.setName("小勾勾");return dog;}
}
3)分别测试xml 和注解驱动
private static void testXml() {System.out.println("准备初始化IOC容器。。。");ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-initmethod.xml");System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");context.close();System.out.println("IOC容器销毁完成。。。");}private static void testAnnotationConfig() {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");applicationContext.close();System.out.println("IOC容器销毁完成。。。");}
输出如下:
准备初始化IOC容器。。。
Cat 构造方法执行了。。。
setName方法执行了。。。
小米米 被初始化了。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
小米米 被销毁了。。。
IOC容器销毁完成。。。-----------------------------准备初始化IOC容器。。。
Dog 构造方法执行了。。。
setName方法执行了。。。
小勾勾被初始化了。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
小勾勾被销毁了。。。
IOC容器销毁完成。。。
由此可以得出结论:在 IOC 容器初始化之前,默认情况下 Bean 已经创建好了,而且完成了初始化动作;容器调用销毁动作时,先销毁所有 Bean ,最后 IOC 容器全部销毁完成。
同时也可以看出来,在 Bean 的生命周期中,是先对属性赋值,后执行 init-method 标记的方法。
@PostConstruct & @PreDestroy
上面的 Cat 和 Dog 都是我们手动声明注册的,但是对于那些使用模式注解的 Bean ,这种方式就不好使了,因为没有可以声明 init-method 和 destroy-method 的地方了。
此时可以使用JSR250 规范提供的 @PostConstruct 和 @PreDestroy 这两个注解,分别对应 init-method 和 destroy-method 。
比如,Spring中常用的模式注解:@Component、@Service、@Repository、@Controller,使用这些注解,Spring容器可以在启动时自动扫描并注册这些Bean,而不需要显式地在XML配置文件中声明或在Java配置类中手动注册。
1)创建Bean
@Component
public class Pen {private Integer ink;public Pen(){System.out.println("钢笔的构造方法");}@PostConstructpublic void addInk() {System.out.println("钢笔中已加满墨水。。。");this.ink = 100;}@PreDestroypublic void outWellInk() {System.out.println("钢笔中的墨水都放干净了。。。");this.ink = 0;}@Overridepublic String toString() {return "Pen{" + "ink=" + ink + '}';}
}
2)测试
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.study.spring.b_jsr250");System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");ctx.close();System.out.println("IOC容器销毁完成。。。");}
}
输出如下:
准备初始化IOC容器。。。
钢笔的构造方法
钢笔中已加满墨水。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
钢笔中的墨水都放干净了。。。
IOC容器销毁完成。。。
可以得出结论:这两个注解实现的效果和 init-method 、 destroy-method 是一样的。
JSR250规范 与 init-method 共存
如果 @PostConstruct 和 @PreDestroy 和 init-method 和 destroy-method 共存,执行顺序是怎样的呢?
1)创建 Bean
public class Pen {private Integer ink;public Pen(){System.out.println("钢笔的构造方法");}public void open() {System.out.println("init method ...打开钢笔");}public void close() {System.out.println("destroy-method - 合上钢笔。。。");}@PostConstructpublic void addInk() {System.out.println("@PostConstruct...钢笔中已加满墨水。。。");this.ink = 100;}@PreDestroypublic void outWellInk() {System.out.println("@PreDestroy...钢笔中的墨水都放干净了。。。");this.ink = 0;}@Overridepublic String toString() {return "Pen{" + "ink=" + ink + '}';}
}
2)创建配置类
@Configuration
public class JSR250Configuration {@Bean(initMethod = "open",destroyMethod = "close")public Pen pen() {return new Pen();}
}
3)测试执行
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(JSR250Configuration.class);System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");applicationContext.close();System.out.println("IOC容器销毁完成。。。");}
}
输出结果:
准备初始化IOC容器。。。
钢笔的构造方法
@PostConstruct...钢笔中已加满墨水。。。
init method ...打开钢笔
IOC容器初始化完成。。。准备销毁IOC容器。。。
@PreDestroy...钢笔中的墨水都放干净了。。。
destroy-method - 合上钢笔。。。
IOC容器销毁完成。。。
可以得出结论:JSR250 规范的执行优先级高于 init / destroy。
InitializingBean & DisposableBean
是 SpringFramework 内部预先定义好的两个关于生命周期的接口,他们的触发时机与 init-method & destroy-method 、 @PostConstruct @PreDestroy一样,都是在 Bean 的初始化和销毁阶段要回调的。
1)创建 Bean
@Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;@Overridepublic void destroy() throws Exception {System.out.println("钢笔中的墨水都放干净了。。。");this.ink = 0;}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("钢笔中已加满墨水。。。");this.ink = 100;}@Overridepublic String toString() {return "Pen{" + "ink=" + ink + '}';}
}
2)测试执行
public class InitializingDisposableAnnoApplication {public static void main(String[] args) throws Exception {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.study.spring.c_initializingbean");System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");ctx.close();System.out.println("IOC容器销毁完成。。。");}
}
输出结果:
准备初始化IOC容器。。。
钢笔中已加满墨水。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
钢笔中的墨水都放干净了。。。
IOC容器销毁完成。。。
三种生命周期并存
当一个 Bean 同时用这三种生命周期控制时,执行顺序又是怎么样的呢?
1)创建 Bean
@Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;public Pen(){System.out.println("构造方法");}public void open() {System.out.println("init-method - 打开钢笔。。。");}public void close() {System.out.println("destroy-method - 合上钢笔。。。");}@PostConstructpublic void addInk() {System.out.println("@PostConstruct 钢笔中已加满墨水。。。");this.ink = 100;}@PreDestroypublic void outwellInk() {System.out.println("@PreDestroy 钢笔中的墨水都放干净了。。。");this.ink = 0;}@Overridepublic void destroy() throws Exception {System.out.println("DisposableBean - 写完字了。。。");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean - 准备写字。。。");}@Overridepublic String toString() {return "Pen{" + "ink=" + ink + '}';}}
2)创建配置类
@Configuration
public class Config {@Bean(initMethod = "open",destroyMethod = "close")public Pen pen(){return new Pen();}
}
3)测试执行
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);System.out.println("IOC容器初始化完成。。。");System.out.println();System.out.println("准备销毁IOC容器。。。");ctx.close();System.out.println("IOC容器销毁完成。。。");}
}
输出结果:
准备初始化IOC容器。。。
构造方法
@PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
IOC容器初始化完成。。。准备销毁IOC容器。。。
@PreDestroy 钢笔中的墨水都放干净了。。。
DisposableBean - 写完字了。。。
destroy-method - 合上钢笔。。。
IOC容器销毁完成。。。
可以看到执行顺序是:@PostConstruct → InitializingBean → init-method 。
原型Bean的生命周期
当面介绍的都是单实例 Bean 的生命周期,而对于原型 Bean,它与单实例 Bean 的生命周期是不一样的。
单实例 Bean 的生命周期是陪着 IOC 容器一起的,容器初始化,单实例 Bean 也跟着初始化(延迟 Bean 例外);
容器销毁,单实例 Bean 也跟着销毁。
原型 Bean 由于每次都是取的时候才产生一个,所以它的生命周期与 IOC 容器无关。
1)创建 Bean
@Component
public class Pen implements InitializingBean, DisposableBean {private Integer ink;public Pen(){System.out.println("构造方法");}public void open() {System.out.println("init-method - 打开钢笔。。。");}public void close() {System.out.println("destroy-method - 合上钢笔。。。");}@PostConstructpublic void addInk() {System.out.println("@PostConstruct 钢笔中已加满墨水。。。");this.ink = 100;}@PreDestroypublic void outWellInk() {System.out.println("@PreDestroy 钢笔中的墨水都放干净了。。。");this.ink = 0;}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean - 准备写字。。。");}@Overridepublic void destroy() throws Exception {System.out.println("DisposableBean - 写完字了。。。");}@Overridepublic String toString() {return "Pen{" + "ink=" + ink + '}';}
}
2)创建配置类
@Configuration
public class Config {@Bean(initMethod = "open",destroyMethod = "close")@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //原型Beanpublic Pen pen(){return new Pen();}
}
3)测试执行
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);System.out.println("IOC容器初始化完成。。。");}
}
输出结果:
准备初始化IOC容器。。。
IOC容器初始化完成。。。
由此得出结论:原型 Bean 的创建不随 IOC 的初始化而创建。
然后,在main 方法中去获取该 Bean,再次执行:
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);System.out.println("IOC容器初始化完成。。。");System.out.println("准备获取pen");Pen pen = ctx.getBean(Pen.class);System.out.println("获取到pen");}
}
输出结果:
准备初始化IOC容器。。。
IOC容器初始化完成。。。
准备获取pen
构造方法
@PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
获取到pen
由此得出结论:原型Bean的初始化动作与单实例Bean完全一致。
接着,我们把销毁 Bean 的代码也加上:
public class Client {public static void main(String[] args) {System.out.println("准备初始化IOC容器。。。");AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);System.out.println("IOC容器初始化完成。。。");System.out.println("准备获取pen");Pen pen = ctx.getBean(Pen.class);System.out.println("获取到pen");System.out.println("用完Pen了,准备销毁。。。");ctx.getBeanFactory().destroyBean(pen);System.out.println("Pen销毁完成。。。");}
}
输出结果:
准备初始化IOC容器。。。
IOC容器初始化完成。。。
准备获取pen
构造方法
@PostConstruct 钢笔中已加满墨水。。。
InitializingBean - 准备写字。。。
init-method - 打开钢笔。。。
获取到pen
用完Pen了,准备销毁。。。
@PreDestroy 钢笔中的墨水都放干净了。。。
DisposableBean - 写完字了。。。
Pen销毁完成。。。
由此得出结论;原型 Bean 在销毁时不处理 destroyMethod 标注的方法。
后置处理器 BeanPostProcessor
BeanPostProcessor是一个容器的扩展点,它可以在 bean 的生命周期过程中,初始化阶段前后添加自定义处理逻辑,并且不同 IOC 容器间的BeanPostProcessor不会相互干预。
也可以配置多个BeanPostProcessor实例,通过设置order属性来控制BeanPostProcessor实例的执行顺序。
1)创建 bean
public class Dog implements InitializingBean {public void initMethod() {System.out.println("initMethod ...");}@PostConstructpublic void postConstruct() {System.out.println("@PostConstruct ...");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean ...");}
}
2)创建配置类
@Configuration
public class Config {@Bean(initMethod = "initMethod")public Dog dog() {return new Dog();}
}
3)创建两个后置处理器
@Component
public class InstantiationTracingBeanPostProcessor1 implements BeanPostProcessor, Ordered {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println("【第一个后置处理器】拦截到Bean的初始化之前:" + bean);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println("【第一个后置处理器】拦截到Bean的初始化之后:" + bean);}return bean;}@Overridepublic int getOrder() {return 1;}
}
@Component
public class InstantiationTracingBeanPostProcessor2 implements BeanPostProcessor, Ordered {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println("【第二个后置处理器】拦截到Bean的初始化之前:" + bean);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Dog) {System.out.println("【第二个后置处理器】拦截到Bean的初始化之后:" + bean);}return bean;}@Overridepublic int getOrder() {return 2;}
}
4)测试执行
public class Client {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.study.spring.postprocessor");}
}
输出结果:
【第一个后置处理器】拦截到Bean的初始化之前:com.study.spring.postprocessor.Dog@7f9fcf7f
【第二个后置处理器】拦截到Bean的初始化之前:com.study.spring.postprocessor.Dog@7f9fcf7f
@PostConstruct ...
InitializingBean ...
initMethod ...
【第一个后置处理器】拦截到Bean的初始化之后:com.study.spring.postprocessor.Dog@7f9fcf7f
【第二个后置处理器】拦截到Bean的初始化之后:com.study.spring.postprocessor.Dog@7f9fcf7f
由此得出 bean 的初始化阶段的全流程:BeanPostProcessor#postProcessBeforeInitialization → @PostConstruct → InitializingBean → init-method → BeanPostProcessor#postProcessAfterInitialization。
参考资料:《从 0 开始深入学习Spring小册》
相关文章:
Spring Bean 的生命周期详解
所谓万物皆对象,对于一个 bean 而言,从出生到死亡,他要经历哪些阶段呢? 生命周期 理解对象的生命周期,可以帮助我们更好的做一些扩展。 一个对象从被创建到被垃圾回收,可以大致分为这 5 个阶段:…...
MySQL【知识改变命运】12
视图 1:什么是视图2:创建视图使用视图(视图的好处)2.1.隐藏敏感字段2.2.对外提供统一访问3:视图和真实表进⾏表连接查询 4:修改视图数据4.1:通过真实表修改数据,会影响视图4.2&#…...
shell编程(完整版)
目录 一、shell脚本解释器 二、shell脚本的执行 三、变量的使用 四、永久环境变量 按用户设置永久环境变量 文件路径: 示例步骤: 删除永久环境变量 五、脚本程序传递参数怎么实现 六、用编程进行数学运算 shell中利用expr进行运算 运算与变量…...
数字逻辑(一)——导论
1.导论 1.1什么是数字逻辑? 数字逻辑是指在数字电路设计、计算机科学领域中对于离散的二进制信号进行逻辑处理、运算、存储和传输的基本原理和方法。 1.2数字量和模拟量的区别 数字量:在时间上和数量上都是离散的、不连续的物理量。模拟量࿱…...
量化交易系统开发-实时行情自动化交易-4.4.做市策略
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来继续说说做市策略原理。 做市策…...
《线性代数的本质》
之前收藏的一门课,刚好期末复习,顺便看一看哈哈 课程链接:【线性代数的本质】合集-转载于3Blue1Brown官方双语】 向量究竟是什么 线性代数中最基础、最根源的组成部分就是向量,需要先明白什么是向量 不同专业对向量的看法 物理专…...
Gbase8s 允许内置用户创建用户以及创建只读权限用户以及利用角色管理普通用户权限
Gbase8s 允许内置用户创建用户以及创建只读权限用户以及利用角色管理普通用户权限 普通安装实例创建数据库以后,DBA权限只有gbasedbt用户。gbasdbt可以创建普通用户,并且给普通用户赋予库及权限或者表级权限。 但是gbasedbt用户口令和操作系统相关,所以想在不提供gbasedbt的…...
24/11/25 视觉笔记 深度传感器和手势识别
本章的目的是开发一个应用程序,使用深度传感器的输出实时检测和跟踪简单的手势。该应用程序将分析每个已捕捉的帧。并执行以下任务。 手部区域分割:通过分析Kinect传感器的深度图输出,在每一帧中提取用户的手部区域,这是通过阈值…...
迄今为止的排序算法总结
迄今为止的排序算法总结 7.10 迄今为止的排序算法总结复杂度和稳定性时间复杂度测试程序sortAlgorithm.hsortAlgorithm.cpptest.cpp 时间复杂度测试结果 7.10 迄今为止的排序算法总结 复杂度和稳定性 排序算法平均情况最好情况最坏情况稳定性空间复杂度选择排序O(n^2)O(n^2)O…...
HTML和CSS 表单、表格练习
HTML和CSS 表格练习 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>HTML表格练习</title>…...
H5流媒体播放器EasyPlayer.js网页直播/点播播放器如果H.265视频在播放器上播放不流畅,可以考虑的解决方案
随着流媒体技术的迅速发展,H5流媒体播放器已成为现代网络视频播放的重要工具。其中,EasyPlayer.js网页直播/点播播放器作为一款功能强大的H5播放器,凭借其全面的协议支持、多种解码方式以及跨平台兼容性,赢得了广泛的关注和应用。…...
Http 转 https 中 Nginx 的详细配置过程
摘要 本节将简要介绍从 HTTP 到 HTTPS 的配置过程,并完整展示 Nginx 的相关配置信息。 经过两天断断续续的调试,终于将 http 变成 https 了。现在说说这个安装 ssl 证书的过程。 服务器是在某云上。这个过程大致分为三个步骤:申请 ssl 证书、…...
【测试工具JMeter篇】JMeter性能测试入门级教程(二)出炉,测试君请各位收藏了!!!
上篇文章:CSDN 我们介绍了JMeter的一些原理介绍,以及安装配置和启动流程,本文我们就来讲讲JMeter如何使用。 一、JMeter目录结构组成 1. 根目录 Jmeter安装包解压后的根目录如下图: 1.1 backups目录:脚本备份目录&am…...
Otter 安装流程
优质博文:IT-BLOG-CN 一、背景 随着公司的发展,订单库的数据目前已达到千万级别,需要进行分表分库,就需要对数据进行迁移,我们使用了otter,这里简单整理下,otter 的安装过程,希望对…...
一文学会Golang里拼接字符串的6种方式(性能对比)
g o l a n g golang golang的 s t r i n g string string类型是不可修改的,对于拼接字符串来说,本质上还是创建一个新的对象将数据放进去。主要有以下几种拼接方式 拼接方式介绍 1.使用 s t r i n g string string自带的运算符 ans ans s2. 使用…...
【笔记】Linux下编译Python3.10.15为动态库同时正确处理OpenSSL3依赖
之前自己第一次编译Python后发现pip会提示无法使用SSL,后来了解到是自己编译时没有配置OpenSSL。这个过程有点曲折,里面有一个坑,怕忘记于是写博客记录一下。 首先是下载OpenSSL,Python3.10.15支持此时最新版的OpenSSL 3.4.0&…...
Go语言获取客户端真实IP
在一些需求中,服务器需要记录客户端的ip地址,要获取ip地址,则需要有http.Request的对象参数传入,以下代码直接放在util中使用。 文件名:ip_utils.go package utilsimport ("context""github.com/spf1…...
大模型论文速递(11.23-11.25)
BlueLM-V3B 关键词:动态分辨率,图像放大,适应性网格化方法 研究问题:如何改进现有的动态分辨率匹配方法以减少在模型训练和部署中的计算复杂度? 方法: 分析现有动态分辨率匹配算法(如LLaVA-…...
维护在线重做日志(二)
迁移和重命名 可以使用操作系统命令重新定位重做日志,然后使用ALTER DATABASE语句使数据库知道它们的新名称(位置)。这个过程是必要的,例如,如果当前用于一些重做日志文件的磁盘将被删除,或者如果数据文件…...
.net core MVC入门(一)
文章目录 项目地址一、环境配置1.1 安装EF core需要包1.2 配置数据库连接二、使用EF创建表2.1 整体流程梳理2.1 建表详细流程三、添加第一个视图3.1整体流程梳理3.1 添加视图,并显示在web里四、使用EF增加Catogory数据,并且读取数据到页面4.1整体流程梳理4.2 实现五、增加Cat…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
