【SpringBean】bean的作用域和bean的生命周期

目录

前言

一 bean的作用域

1. singleton——唯一 bean 实例

2. prototype——每次请求都会创建一个新的 bean 实例

3. request——每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效

4. session——每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效

5. globalSession

二 bean的生命周期

initialization 和 destroy

实现*Aware接口 在Bean中使用Spring框架的一些对象

BeanPostProcessor

总结

单例管理的对象

非单例管理的对象


前言

在 Spring 中,那些组成应用程序的主体及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IOC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。

Spring中的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢? 例如对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框架之后,每个Action都是单例的,那么对于Spring托管的单例Service Bean,如何保证其安全呢? Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于 JVM,每个 JVM 内只有一个实例。

在大多数情况下。单例 bean 是很理想的方案。不过,有时候你可能会发现你所使用的类是易变的,它们会保持一些状态,因此重用是不安全的。在这种情况下,将 class 声明为单例的就不是那么明智了。因为对象会被污染,稍后重用的时候会出现意想不到的问题。所以 Spring 定义了多种作用域的bean。

一 bean的作用域

创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的“配方”。把bean定义看成一个配方很有意义,它与class很类似,只根据一张“处方”就可以创建多个实例。不仅可以控制注入到对象中的各种依赖和配置值,还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域,而不必在Java Class级定义作用域。Spring Framework支持五种作用域,分别阐述如下表。

五种作用域中,request、sessionglobal session 三种作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于 web 的 Spring ApplicationContext 环境。

1. singleton——唯一 bean 实例

当一个 bean 的作用域为 singleton,那么Spring IoC容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回bean的同一实例。 singleton 是单例类型(对应于单例模式),就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,但我们可以指定Bean节点的 lazy-init=”true” 来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。 每次获取到的对象都是同一个对象。注意,singleton 作用域是Spring中的缺省作用域。要在XML中将 bean 定义成 singleton ,可以这样配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

也可以通过 @Scope 注解(它可以显示指定bean的作用范围。)的方式

@Service
@Scope("singleton")
public class ServiceImpl{
​
}

2. prototype——每次请求都会创建一个新的 bean 实例

当一个bean的作用域为 prototype,表示一个 bean 定义对应多个对象实例。 prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。 在 XML 中将 bean 定义成 prototype ,可以这样配置:

<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
 或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

通过 @Scope 注解的方式实现就不做演示了。

3. request——每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效

request只适用于Web程序,每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,当请求结束后,该对象的生命周期即告结束。 在 XML 中将 bean 定义成 request ,可以这样配置:

<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

4. session——每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效

session只适用于Web程序,session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效.与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的 HTTP session 中根据 userPreferences 创建的实例,将不会看到这些特定于某个 HTTP session 的状态变化。当HTTP session最终被废弃的时候,在该HTTP session作用域内的bean也会被废弃掉。

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

5. globalSession

global session 作用域类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portle t所共享。在global session 作用域中定义的 bean 被限定于全局portlet Session的生命周期范围内。

 

二 bean的生命周期

Spring Bean是Spring应用中最最重要的部分了。所以来看看Spring容器在初始化一个bean的时候会做那些事情,顺序是怎样的,在容器关闭的时候,又会做哪些事情。

spring版本:4.2.3.RELEASE 鉴于Spring源码是用gradle构建的,我也决定舍弃我大maven,尝试下洪菊推荐过的gradle。运行beanLifeCycle模块下的junit test即可在控制台看到如下输出,可以清楚了解Spring容器在创建,初始化和销毁Bean的时候依次做了那些事情。

Spring容器初始化
=====================================
调用GiraffeService无参构造函数
GiraffeService中利用set方法设置属性值
调用setBeanName:: Bean Name defined in context=giraffeService
调用setBeanClassLoader,ClassLoader Name = sun.misc.Launcher$AppClassLoader
调用setBeanFactory,setBeanFactory:: giraffe bean singleton=true
调用setEnvironment
调用setResourceLoader:: Resource File Name=spring-beans.xml
调用setApplicationEventPublisher
调用setApplicationContext:: Bean Definition Names=[giraffeService, org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#0, com.giraffe.spring.service.GiraffeServicePostProcessor#0]
执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=giraffeService
调用PostConstruct注解标注的方法
执行InitializingBean接口的afterPropertiesSet方法
执行配置的init-method
执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=giraffeService
Spring容器初始化完毕
=====================================
从容器中获取Bean
giraffe Name=李光洙
=====================================
调用preDestroy注解标注的方法
执行DisposableBean接口的destroy方法
执行配置的destroy-method
Spring容器关闭

先来看看,Spring在Bean从创建到销毁的生命周期中可能做得事情。

initialization 和 destroy

有时我们需要在Bean属性值set好之后和Bean销毁之前做一些事情,比如检查Bean中某个属性是否被正常的设置好值了。Spring框架提供了多种方法让我们可以在Spring Bean的生命周期中执行initialization和pre-destroy方法。

1.实现InitializingBean和DisposableBean接口

这两个接口都只包含一个方法。通过实现InitializingBean接口的afterPropertiesSet()方法可以在Bean属性值设置好之后做一些操作,实现DisposableBean接口的destroy()方法可以在销毁Bean之前做一些操作。

例子如下:

public class GiraffeService implements InitializingBean,DisposableBean {@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("执行InitializingBean接口的afterPropertiesSet方法");}@Overridepublic void destroy() throws Exception {System.out.println("执行DisposableBean接口的destroy方法");}
}

这种方法比较简单,但是不建议使用。因为这样会将Bean的实现和Spring框架耦合在一起。

2.在bean的配置文件中指定init-method和destroy-method方法

Spring允许我们创建自己的 init 方法和 destroy 方法,只要在 Bean 的配置文件中指定 init-method 和 destroy-method 的值就可以在 Bean 初始化时和销毁之前执行一些操作。

例子如下:

public class GiraffeService {//通过<bean>的destroy-method属性指定的销毁方法public void destroyMethod() throws Exception {System.out.println("执行配置的destroy-method");}//通过<bean>的init-method属性指定的初始化方法public void initMethod() throws Exception {System.out.println("执行配置的init-method");}
}

配置文件中的配置:

<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService" init-method="initMethod" destroy-method="destroyMethod">
</bean>

需要注意的是自定义的init-method和post-method方法可以抛异常但是不能有参数。

这种方式比较推荐,因为可以自己创建方法,无需将Bean的实现直接依赖于spring的框架。

3.使用@PostConstruct和@PreDestroy注解

除了xml配置的方式,Spring 也支持用 @PostConstruct@PreDestroy注解来指定 initdestroy 方法。这两个注解均在javax.annotation 包中。为了注解可以生效,需要在配置文件中定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config

例子如下:

public class GiraffeService {@PostConstructpublic void initPostConstruct(){System.out.println("执行PostConstruct注解标注的方法");}@PreDestroypublic void preDestroy(){System.out.println("执行preDestroy注解标注的方法");}
}

配置文件:

  
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
​

实现*Aware接口 在Bean中使用Spring框架的一些对象

有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取 ServletContext 的一些参数,获取 ApplicaitionContext 中的 BeanDefinition 的名字,获取 Bean 在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware的接口。

这些接口均继承于org.springframework.beans.factory.Aware标记接口,并提供一个将由 Bean 实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用。 网上说,这些接口是利用观察者模式实现的,类似于servlet listeners,目前还不明白,不过这也不在本文的讨论范围内。 介绍一些重要的Aware接口:

  • ApplicationContextAware: 获得ApplicationContext对象,可以用来获取所有Bean definition的名字。

  • BeanFactoryAware:获得BeanFactory对象,可以用来检测Bean的作用域。

  • BeanNameAware:获得Bean在配置文件中定义的名字。

  • ResourceLoaderAware:获得ResourceLoader对象,可以获得classpath中某个文件。

  • ServletContextAware:在一个MVC应用中可以获取ServletContext对象,可以读取context中的参数。

  • ServletConfigAware: 在一个MVC应用中可以获取ServletConfig对象,可以读取config中的参数。

public class GiraffeService implements   ApplicationContextAware,ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("执行setBeanClassLoader,ClassLoader Name = " + classLoader.getClass().getName());}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("执行setBeanFactory,setBeanFactory:: giraffe bean singleton=" +  beanFactory.isSingleton("giraffeService"));}@Overridepublic void setBeanName(String s) {System.out.println("执行setBeanName:: Bean Name defined in context="+ s);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("执行setApplicationContext:: Bean Definition Names="+ Arrays.toString(applicationContext.getBeanDefinitionNames()));}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {System.out.println("执行setApplicationEventPublisher");}@Overridepublic void setEnvironment(Environment environment) {System.out.println("执行setEnvironment");}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {Resource resource = resourceLoader.getResource("classpath:spring-beans.xml");System.out.println("执行setResourceLoader:: Resource File Name="+ resource.getFilename());}@Overridepublic void setImportMetadata(AnnotationMetadata annotationMetadata) {System.out.println("执行setImportMetadata");}
}

BeanPostProcessor

上面的*Aware接口是针对某个实现这些接口的Bean定制初始化的过程, Spring同样可以针对容器中的所有Bean,或者某些Bean定制初始化过程,只需提供一个实现BeanPostProcessor接口的类即可。 该接口中包含两个方法,postProcessBeforeInitialization和postProcessAfterInitialization。 postProcessBeforeInitialization方法会在容器中的Bean初始化之前执行, postProcessAfterInitialization方法在容器中的Bean初始化之后执行。

例子如下:

public class CustomerBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);return bean;}
}

要将BeanPostProcessor的Bean像其他Bean一样定义在配置文件中

<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>

总结

所以。。。结合第一节控制台输出的内容,Spring Bean的生命周期是这样纸的:

  • Bean容器找到配置文件中 Spring Bean 的定义。

  • Bean容器利用Java Reflection API创建一个Bean的实例。

  • 如果涉及到一些属性值 利用set方法设置一些属性值。

  • 如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。

  • 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。

  • 如果Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。

  • 与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。

  • 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法

  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。

  • 如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。

  • 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法

  • 当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。

  • 当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。

用图表示一下(图来源:http://www.jianshu.com/p/d00539babca5):

与之比较类似的中文版本:

其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口,针对bean的单例和非单例来描述下bean的生命周期:

单例管理的对象

当scope=”singleton”,即默认情况下,会在启动容器时(即实例化容器时)时实例化。但我们可以指定Bean节点的lazy-init=”true”来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。如下配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>  

如果想对所有的默认单例bean都应用延迟初始化,可以在根节点beans设置default-lazy-init属性为true,如下所示:

<beans default-lazy-init="true" …>

默认情况下,Spring 在读取 xml 文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用 init-method 属性值中所指定的方法。对象在被销毁的时候,会调用 destroy-method 属性值中所指定的方法(例如调用Container.destroy()方法的时候)。写一个测试类,代码如下:

public class LifeBean {private String name;  
​public LifeBean(){  System.out.println("LifeBean()构造函数");  }  public String getName() {  return name;  }  
​public void setName(String name) {  System.out.println("setName()");  this.name = name;  }  
​public void init(){  System.out.println("this is init of lifeBean");  }  
​public void destory(){  System.out.println("this is destory of lifeBean " + this);  }  
}

 life.xml配置如下:

<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" init-method="init" destroy-method="destory" lazy-init="true"/>

测试代码:

public class LifeTest {@Test public void test() {AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");LifeBean life1 = (LifeBean)container.getBean("life");System.out.println(life1);container.close();}
}

运行结果:

LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1

非单例管理的对象

scope=”prototype”时,容器也会延迟初始化 bean,Spring 读取xml 文件的时候,并不会立刻创建对象,而是在第一次请求该 bean 时才初始化(如调用getBean方法时)。在第一次请求每一个 prototype 的bean 时,Spring容器都会调用其构造器创建这个对象,然后调用init-method属性值中所指定的方法。对象销毁的时候,Spring 容器不会帮我们调用任何方法,因为是非单例,这个类型的对象有很多个,Spring容器一旦把这个对象交给你之后,就不再管理这个对象了。

为了测试prototype bean的生命周期life.xml配置如下:

<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>

测试程序:

public class LifeTest {@Test public void test() {AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");LifeBean life1 = (LifeBean)container.getBean("life_singleton");System.out.println(life1);
​LifeBean life3 = (LifeBean)container.getBean("life_prototype");System.out.println(life3);container.close();}
}

运行结果:

LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1

可以发现,对于作用域为 prototype 的 bean ,其destroy方法并没有被调用。如果 bean 的 scope 设为prototype时,当容器关闭时,destroy 方法不会被调用。对于 prototype 作用域的 bean,有一点非常重要,那就是 Spring不能对一个 prototype bean 的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。 不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用)。谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java new操作的替代者,任何迟于该时间点的生命周期事宜都得交由客户端来处理。

Spring 容器可以管理 singleton 作用域下 bean 的生命周期,在此作用域下,Spring 能够精确地知道bean何时被创建,何时初始化完成,以及何时被销毁。而对于 prototype 作用域的bean,Spring只负责创建,当容器创建了 bean 的实例后,bean 的实例就交给了客户端的代码管理,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的bean的生命周期。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/714749.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

程序员的金三银四求职宝典!

目录 ​编辑 程序员的金三银四求职宝典 一、为什么金三银四是程序员求职的黄金时期&#xff1f; 二、如何准备金三银四求职&#xff1f; 1. 完善简历 2. 增强技术能力 3. 提前考虑目标公司 4. 提前准备面试 三、程序员求职的常见面试题 1. 数据结构和算法 2. 数据库 …

一次电脑感染Synaptics Pointing Device Driver病毒的经历,分享下经验

没想到作为使用电脑多年的老司机也会电脑中病毒&#xff0c;周末玩电脑的时候突然电脑很卡&#xff0c;然后自动重启&#xff0c;奇怪&#xff0c;之前没出现这个情况。 重启后电脑开机等了几十秒&#xff0c;打开任务管理器查看开机进程&#xff0c;果然发现有个Synaptics Po…

LeetCode 刷题 [C++] 第121题.买卖股票的最佳时机

题目描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…

php儿童服装销售管理系统计算机毕业设计项目包运行调试

php mysql儿童服装销售网 功能&#xff1a;前台后台 前台&#xff1a; 1.服装资讯 文章标题列表 详情 2.服装选购中心 分页查看图文列表 详情 3.用户注册 登陆 退出 4.服装加入收藏 5.加入购物车 6.对服装进行评论 会员中心&#xff1a; 1.我的账户 查看 修改 2.我的收藏 查看 …

STM32 中断流程介绍

STM32可以产生中断的事件多种多样&#xff0c;比如&#xff1a;定时器时间结束、串口接收到数据、某个GPIO检测到电平变化等等等等。 1、STM32 gpio 中断处理流程介绍 1、从引脚进入的高低电平首先由输入驱动器处理&#xff0c;如下图 2、经过输入驱动器处理后的信号会进…

c++基础知识补充4

单独使用词汇 using std::cout; 隐式类型转换型初始化&#xff1a;如A a1,,此时可以形象地理解为int i1;double ji;&#xff0c;此时1可以认为创建了一个值为1的临时对象&#xff0c;然后对目标对象进行赋值&#xff0c;当对象为多参数时&#xff0c;使用&#xff08;1&#xf…

c1-周考2

c1-第二周 9月-技能1.一个岛上有两种神奇动物&#xff0c;其中神奇鸟类2个头3只脚&#xff0c;神奇兽类3个头8只脚。游客在浓雾中看到一群动物&#xff0c;共看到35个头和110只脚&#xff0c;求可能的鸟类和兽类的只数2.构建一个长度为5的数组&#xff0c;并且实现下列要求3.构…

鬼屋游戏c++

c #include <iostream> #include <string> #include <vector> #include <cstdlib> // 用于随机数生成 #include <ctime> // 用于随机数种子using namespace std;// 定义房间结构体 struct Room {string description;bool hasKey;bool hasClue…

babylonjs入门-自由相机 FreeCamera

基于babylonjs封装的一些功能和插件 &#xff0c;希望有更多的小伙伴一起玩babylonjs&#xff1b; 欢迎加群&#xff08;点击群号传送&#xff09;&#xff1a;464146715 官方文档 中文文档 案例传送门 懒得打字 粘贴复制 一气呵成 ​

计算机网络——22TCP拥塞

TCP拥塞 TCP拥塞控制机制 端到端的拥塞控制机制 路由器不向主机有关拥塞的反馈信息 路由器的负担较轻符合网络核心简单的TCP/IP架构原则 端系统根据自身得到的信息&#xff0c;判断是否发生拥塞&#xff0c;从而采取动作 拥塞控制的几个问题 如何检测拥塞 轻微拥塞拥塞 控…

Http基础之http协议、无状态协议、状态码、http报文、跨域-cors

Http基础 HTTP基础HTTP协议请求方法持久连接管线化 无状态协议使用Cookie状态管理 状态码1XX2XX OK200 OK204 NO Content206 Content-Range 3XX 重定向301302304307 4XX400401403404 5XX500503 HTTP报文请求报文响应报文通用首部字段Cache-ControlConnectionDate请求首部字段Ac…

JVM 第四部分—垃圾回收相关概念 2

System.gc() 在默认情况下&#xff0c;通过System.gc()或者Runtime.getRuntime().gc()的调用&#xff0c;会显式触发Full GC&#xff0c;同时对老年代和新生代进行回收&#xff0c;尝试释放被丢弃对象占用的内存 然而System.gc()调用附带一个免责声明&#xff0c;无法保证对垃…

博途PLC 面向对象系列之“双通气缸功能块“(SCL代码)

1、面向对象系列之找对象 https://rxxw-control.blog.csdn.net/article/details/136150027https://rxxw-control.blog.csdn.net/article/details/1361500272、博途PLC 面向对象系列之"单通气缸功能块" https://rxxw-control.blog.csdn.net/article/details/1363399…

Spark(1)-wordCount入门

1. 创建Maven项目 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

JavaScript继承 寄生组合式继承 extends

JavaScript继承 1、JS 的继承到底有多少种实现方式呢? 2、ES6 的 extends 关键字是用哪种继承方式实现的呢? 继承种类 原型链继承 function Parent1() {this.name parentlthis.play [1, 2, 3] }function Child1() {this.type child2 }Child1.prototype new Parent1(…

三天学会阿里分布式事务框架Seata-seata事务日志mysql持久化配置

锋哥原创的分布式事务框架Seata视频教程&#xff1a; 实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;_哔哩哔哩_bilibili实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;共计10条视频&…

上位机图像处理和嵌入式模块部署(当前机器视觉新形态)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 过去的机器视觉处理&#xff0c;大部分都是集中在上位机、或者是服务器领域&#xff0c;这种形式维持了很长的时间。这种业务形态下&#xff0c;无…

windows 11 蓝牙突然消失

解决方法&#xff1a; 1.WinX&#xff0c;点击设备管理器 2.选中蓝牙&#xff0c;右键更新驱动。 3.然后就可以出现了&#xff0c;如下图

程序员是如何看待“祖传代码”的?

目录 ​编辑 程序员是如何看待“祖传代码”的&#xff1f; 一、什么是“祖传代码”&#xff1f; 二、“祖传代码”的利弊 1. 可以节省开发成本 2. 可能引入安全隐患 3. 可能增加系统的维护难度 三、祖传代对程序员的影响 1. 丰富程序员的技能和知识 2. 提高程序员的创…

Python——Tchisla求解器(暴力搜索法)

Tchisla简介 最近玩到一个挺有意思的数字解密小游戏《Tchisla》&#xff0c;其规则类似算24点&#xff0c;也是利用一些数学运算和初始数字计算出目标数字&#xff0c;与算24点不同的是&#xff0c;Tchisla允许不限次数地使用一种初始数字&#xff08;1~9&#xff09;&#xf…