Spring的生命周期

news2024/11/22 17:12:22

Spring作为当前Java最流行、最强大的轻量级框架,受到了程序员的热烈欢迎。准确的了解Spring Bean的生命周期是非常必要的。我们通常使用ApplicationContext作为Spring容器。这里,我们讲的也是 ApplicationContext中Bean的生命周期。而实际上BeanFactory也是差不多的,只不过处理器需要手动注册。
一、生命周期流程图:

Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。

在这里插入图片描述
在这里插入图片描述
若容器注册了以上各种接口,程序那么将会按照以上的流程进行。下面将仔细讲解各接口作用。

二、各种接口方法分类

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

1、Bean自身的方法  :  这个包括了Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法

2、Bean级生命周期接口方法  :  这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

3、容器级生命周期接口方法  :  这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

4、工厂后处理器接口方法  :  这个包括了BeanFactoryPostProcessor等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

三、演示

我们用一个简单的Spring Bean来演示一下Spring Bean的生命周期。

1、首先是一个简单的Spring Bean,调用Bean自身的方法和Bean级生命周期接口方法,为了方便演示,它实现了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这4个接口,同时有2个方法,对应配置文件中的init-method和destroy-method。如下:

package springBeanTest;  
  
import org.springframework.beans.BeansException;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.BeanFactoryAware;  
import org.springframework.beans.factory.BeanNameAware;  
import org.springframework.beans.factory.DisposableBean;  
import org.springframework.beans.factory.InitializingBean;  
  
/** 
 * @author qsk 
 */  
public class Person implements BeanFactoryAware, BeanNameAware,  
        InitializingBean, DisposableBean {  
  
    private String name;  
    private String address;  
    private int phone;  
  
    private BeanFactory beanFactory;  
    private String beanName;  
  
    public Person() {  
        System.out.println("【构造器】调用Person的构造器实例化");  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        System.out.println("【注入属性】注入属性name");  
        this.name = name;  
    }  
  
    public String getAddress() {  
        return address;  
    }  
  
    public void setAddress(String address) {  
        System.out.println("【注入属性】注入属性address");  
        this.address = address;  
    }  
  
    public int getPhone() {  
        return phone;  
    }  
  
    public void setPhone(int phone) {  
        System.out.println("【注入属性】注入属性phone");  
        this.phone = phone;  
    }  
  
    @Override  
    public String toString() {  
        return "Person [address=" + address + ", name=" + name + ", phone="  
                + phone + "]";  
    }  
  
    // 这是BeanFactoryAware接口方法  
    @Override  
    public void setBeanFactory(BeanFactory arg0) throws BeansException {  
        System.out  
                .println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");  
        this.beanFactory = arg0;  
    }  
  
    // 这是BeanNameAware接口方法  
    @Override  
    public void setBeanName(String arg0) {  
        System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");  
        this.beanName = arg0;  
    }  
  
    // 这是InitializingBean接口方法  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        System.out  
                .println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");  
    }  
  
    // 这是DiposibleBean接口方法  
    @Override  
    public void destroy() throws Exception {  
        System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");  
    }  
  
    // 通过<bean>的init-method属性指定的初始化方法  
    public void myInit() {  
        System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");  
    }  
  
    // 通过<bean>的destroy-method属性指定的初始化方法  
    public void myDestory() {  
        System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");  
    }  
}

2、接下来是演示BeanPostProcessor接口的方法,如下:

package springBeanTest;  
  
import org.springframework.beans.BeansException;  
import org.springframework.beans.factory.config.BeanPostProcessor;  
  
public class MyBeanPostProcessor implements BeanPostProcessor {  
  
    public MyBeanPostProcessor() {  
        super();  
        System.out.println("这是BeanPostProcessor实现类构造器!!");  
        // TODO Auto-generated constructor stub  
    }  
  
    @Override  
    public Object postProcessAfterInitialization(Object arg0, String arg1)  
            throws BeansException {  
        System.out  
                .println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!");  
        return arg0;  
    }  
  
    @Override  
    public Object postProcessBeforeInitialization(Object arg0, String arg1)  
            throws BeansException {  
        System.out  
                .println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!");  
        return arg0;  
    }  
}

如上,BeanPostProcessor接口包括2个方法postProcessAfterInitialization和postProcessBeforeInitialization,这两个方法的第一个参数都是要处理的Bean对象,第二个参数都是Bean的name。返回值也都是要处理的Bean对象。这里要注意。

3、InstantiationAwareBeanPostProcessor接口本质是BeanPostProcessor的子接口,一般我们继承Spring为其提供的适配器类InstantiationAwareBeanPostProcessorAdapter来使用它,如下:

package springBeanTest;  
  
import java.beans.PropertyDescriptor;  
  
import org.springframework.beans.BeansException;  
import org.springframework.beans.PropertyValues;  
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;  
  
public class MyInstantiationAwareBeanPostProcessor extends  
        InstantiationAwareBeanPostProcessorAdapter {  
    public MyInstantiationAwareBeanPostProcessor() {  
        super();  
        System.out  
                .println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");  
    }  
  
    // 接口方法、实例化Bean之前调用  
    @Override  
    public Object postProcessBeforeInstantiation(Class beanClass,  
            String beanName) throws BeansException {  
        System.out  
                .println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");  
        return null;  
    }  
  
    // 接口方法、实例化Bean之后调用  
    @Override  
    public Object postProcessAfterInitialization(Object bean, String beanName)  
            throws BeansException {  
        System.out  
                .println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");  
        return bean;  
    }  
  
    // 接口方法、设置某个属性时调用  
    @Override  
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,  
            PropertyDescriptor[] pds, Object bean, String beanName)  
            throws BeansException {  
        System.out  
                .println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");  
        return pvs;  
    }  
}

这个有3个方法,其中第二个方法postProcessAfterInitialization就是重写了BeanPostProcessor的方法。第三个方法postProcessPropertyValues用来操作属性,返回值也应该是PropertyValues对象。

4、演示工厂后处理器接口方法,如下:

package springBeanTest;  
  
import org.springframework.beans.BeansException;  
import org.springframework.beans.factory.config.BeanDefinition;  
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
  
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {  
  
    public MyBeanFactoryPostProcessor() {  
        super();  
        System.out.println("这是BeanFactoryPostProcessor实现类构造器!!");  
    }  
  
    @Override  
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)  
            throws BeansException {  
        System.out  
                .println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");  
        BeanDefinition bd = arg0.getBeanDefinition("person");  
        bd.getPropertyValues().addPropertyValue("phone", "110");  
    }  
  
}

5、配置文件如下beans.xml,很简单,使用ApplicationContext,处理器不用手动注册:

<?xml version="1.0" encoding="UTF-8"?>  
  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="  
            http://www.springframework.org/schema/beans   
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  
    <bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">  
    </bean>  
  
    <bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">  
    </bean>  
  
    <bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">  
    </bean>  
      
    <bean id="person" class="springBeanTest.Person" init-method="myInit"  
        destroy-method="myDestory" scope="singleton" p:name="张三" p:address="广州"  
        p:phone="15900000000" />  
  
</beans>

6、下面测试一下:

package springBeanTest;  
  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
public class BeanLifeCycle {  
  
    public static void main(String[] args) {  
  
        System.out.println("现在开始初始化容器");  
  
        ApplicationContext factory = new ClassPathXmlApplicationContext(  
                "springBeanTest/beans.xml");  
        System.out.println("容器初始化成功");  
        // 得到Preson,并使用  
        Person person = factory.getBean("person", Person.class);  
        System.out.println(person);  
  
        System.out.println("现在开始关闭容器!");  
        ((ClassPathXmlApplicationContext) factory).registerShutdownHook();  
    }  
}

关闭容器使用的是实际是AbstractApplicationContext的钩子方法。

我们来看一下结果:

现在开始初始化容器
2014-5-18 15:46:20 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19a0c7c: startup date [Sun May 18 15:46:20 CST 2014]; root of context hierarchy
2014-5-18 15:46:20 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [springBeanTest/beans.xml]
这是BeanFactoryPostProcessor实现类构造器!!
BeanFactoryPostProcessor调用postProcessBeanFactory方法
这是BeanPostProcessor实现类构造器!!
这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!
2014-5-18 15:46:20 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@9934d4: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,person]; root of factory hierarchy
InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
【构造器】调用Person的构造器实例化
InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
【注入属性】注入属性address
【注入属性】注入属性name
【注入属性】注入属性phone
【BeanNameAware接口】调用BeanNameAware.setBeanName()BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!
【InitializingBean接口】调用InitializingBean.afterPropertiesSet()
【init-method】调用<bean>的init-method属性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!
InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
容器初始化成功
Person [address=广州, name=张三, phone=110]
现在开始关闭容器!
【DiposibleBean接口】调用DiposibleBean.destory()
【destroy-method】调用<bean>的destroy-method属性指定的初始化方法

/**

  • ————————如果觉得本博文还行,别忘了推荐一下哦,谢谢!
  • 作者:Rsun
  • 欢迎转载,请保留此段声明。
    */
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 public class BeanLifeCycle {
 
     public static void main(String[] args) {
 
         System.out.println("现在开始初始化容器");
         
         ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
         System.out.println("容器初始化成功");    
         //得到Preson,并使用
         Person person = factory.getBean("person",Person.class);
         System.out.println(person);
         
         System.out.println("现在开始关闭容器!");
         ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
     }
 }

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

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

相关文章

【云原生进阶之容器】第四章Operator原理4.1节--定制资源(Custom Resource)

1 定制资源概述 定制资源(Custom Resource) 是对 Kubernetes API 的扩展。 本页讨论何时向 Kubernetes 集群添加定制资源,何时使用独立的服务。 1.1 定制资源 资源(Resource) 是 Kubernetes API 中的一个端点, 其中存储的是某个类别的 API 对象的一个集合。 例如内置的 …

Revit中墙连接方式和墙连接显示及修改问题

关于Revit墙连接方式、显示及其调整修改的理解&#xff0c;首先我们要来理清楚几个问题 1、什么是Revit墙连接&#xff1f; 在Revit里墙与墙之间的连接就是墙连接&#xff0c;它可以是同类型墙之间的连接&#xff0c;也可以是不同类型墙之间的连接&#xff0c;可以是2堵墙、3…

【链表】leetcode面试题 02.07. 链表相交(C/C++/Java/Js)

leetcode面试题 02.07. 链表相交1 题目2 思路2.1 思路一2.2 思路二(强推--5行代码&#xff09;3 代码3.1 C版本3.1.1思路一&#xff1a;3.1.2 思路二3.2 C版本3.2.1 思路一3.2.2 思路二3.3 Java版本3.3.1 思路一3.3.2 思路二3.4 JavaScript版本4 总结1 题目 给你两个单链表的头…

【进阶C语言】动态内存管理+柔性数组

文章目录1.动态内存的开辟内存的布局内存池内存碎片内存泄漏2.动态内存函数malloc功能函数calloc功能函数realloc功能函数开辟时遇到的两种情况free功能函数3.  建议4.柔性数组特性&#xff1a;定义使用优点1.动态内存的开辟 内存的布局 我们常用的内存开辟函数都是在堆区开辟…

几个特殊的运算符重载(前置\后置++、前置\后置--、<<、>>)

几个特殊的运算符重载 概念 运算符重载是一个非常重要的概念&#xff0c;在运算符重载中我们可以重新定义 运算符 的具体含义&#xff0c;一个运算符重载函数的定义是 T operator 运算符 (参数) &#xff0c;对于运算符重载有以下重点。 以下讨论的都是双操作数的运算符 双操…

uniapp: 本应用使用HBuilderX x.x.xx 或对应的cli版本编译,而手机端SDK版本是 x.x.xx。不匹配的版本可能造成应用异常。

目录场景与问题描述&#xff1a;原因分析&#xff1a;解决方案&#xff1a;方案一&#xff1a;更新HbuilderX版本方案二&#xff1a;设置固定的版本方案三&#xff1a;忽略版本&#xff08;不推荐&#xff09;场景与问题描述&#xff1a; 项目场景&#xff1a;示例:通过使用Hb…

【docker13】Dockfile

1.Dockerfile是什么 Dockerfile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像所需的指令和参数构成的脚本 自己的理解是&#xff1a;将多次繁琐的commit命令构成一个Dockerfile文本然后一次性执行完成&#xff0c;可以简化复杂程度 Dockerfile官网 构建三部…

Docker部署 registry

系列文章目录 Docker部署 registry Docker搭建 svn Docker部署 Harbor Docker 部署SQL Server 2017 Docker 安装 MS SqlServer Docker部署 Oracle12c Docker部署Jenkins Docker部署 registry系列文章目录前言一、registry搭建二、使用步骤1. pull registry2. run image3. 验证…

通过gcloud创建Google Kubernetes Engine(GKE)并通过kubectl访问

1 简介 GKE(Google Kubernetes Engine)是一个K8s平台&#xff0c; 我们可以使用gcloud来创建GKE集群。在开始之前&#xff0c;可以查看&#xff1a;《初始化一个GCP项目并用gcloud访问操作》。 2 创建GKE集群 2.1 打开API 在创建集群之前&#xff0c;需要打开Google API&am…

图扑数字孪生水利工程,助力水资源合理利用

前言从大禹治水到三峡大坝的建造&#xff0c;人类为控制和调配自然界的地表水和地下水&#xff0c;修建了许多的水利工程。对水资源进行了广泛的开发利用&#xff0c;诸如农业灌溉、工业和生活用水、水力发电、航运、港口运输、淡水养殖、旅游等。将图扑软件与 GIS、粒子仿真、…

力扣算法(Java实现)—字符串入门(9题)

文章目录1.反转字符串2.整数反转3.字符串中的第一个唯一字符4.有效的字母异位词5.验证回文串6.字符串转换整数 (atoi)7.实现strStr()8.外观数列9.最长公共前缀&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e; 更多资源链接&#xff0c;欢迎访问作者gitee仓…

STM32那些事

STM32芯片型号命名方式STM32开发板的GPIO编程GPIO的函数调用顺序&#xff1a;&#xff08;1&#xff09;使能GPIO时钟&#xff1a;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);第一个参数是GPIO对象&#xff0c;第二个参数是枚举使能&#xff08;2&#xff09;初始化…

Python - 数据容器tuple(元组)

目录 定义元组 元组的相关操作 修改元组 元组的删除 转换为元组tuple 定义元组 元组同列表一样&#xff0c;都是可以封装多个、不同类型的元素在内。 但最大的不同点在于&#xff1a;元组一旦定义完成&#xff0c;就不可修改 元组定义&#xff1a;定义元组使用小括号&…

第二章.线性回归以及非线性回归—梯度下降法

第二章.线性回归以及非线性回归 2.5 梯度下降法 1.流程&#xff1a; 初始化θ0,θ1 不断改变θ0,θ1&#xff0c;直到J(θ0,θ1)到达一个全局最小值或局部极小值 2.图像分析&#xff1a; 1).图像层面分析代价函数&#xff1a; ①.红色区域表示代价函数的值比较大&#xff0…

leetcode 1443.Minimum Time to Collect All Apples in a Tree(收集苹果所需最短时间)

给出节点个数n, edges是连接的边&#xff0c;[a,b]是连接的两个顶点。 hasApple表示第 i 个顶点上是否有苹果。 走一条边需要耗时1s, 从顶点0出发&#xff0c;最后回到顶点0, 问收集所有苹果所需最短的时间。 思路&#xff1a; &#xff08;1&#xff09;DFS 可以把问题简化…

pdf文档控件Aspose.PDF for .NET 授权须知

Aspose.PDF是一款高级PDF处理API&#xff0c;可以在跨平台应用程序中轻松生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现&#xff0c;保护和打印文档。无需使用Adobe Acrobat。此外&#xff0c;API提供压缩选项&#xff0c;表创建和处理&#xff0c;图形和图像功能&…

[ 解决报错篇 ] tomcat 执行 startup.bat 文件报错 -- tomcat 启动失败(安装 java 环境并配置环境变量)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Linux——팔 gdb部分基础知识以及操作系统的初级理解

文章目录一、gdb部分基础知识1、打断点2、逐语句过程3、监视&#xff0c;内存4、部分功能指令二、进程概念的初级理解1、冯-诺依曼体系结构2、操作系统的初级理解一、gdb部分基础知识 承接上一篇。 1、打断点 放一下全部代码 1 #include <stdio.h>2 3 int ADD(int n)4…

vs2017调试ffprobe源码

鄙人之前写过vs2017调试ffmpeg源码 现在由于需要分析视频文件里面的具体帧情况&#xff0c;需要用到ffprobe工具&#xff0c;为此本篇博客搭建vs2017工程&#xff0c;可以调试ffprobe&#xff0c;ffprobe比ffmpeg简单很多。 首先找到ffmpeg的编译目录&#xff0c;将下列三个文…

结构体内存对齐与位段详解

文章目录前言一、内存对齐1.内存对齐的规则2. 内存对齐的具体实例与运用3.为什么会有内存对齐&#xff1f;4.修改默认对齐数二、位段1.什么是位段2.位段的例子3.位段的优缺点结语前言 学习了结构体&#xff0c;你会算结构体的占用字节数吗&#xff0c;许多人恐怕摇头&#xff0…