Spring之bean的生命周期

目录

一、bean生命周期的原理

二、Spring的单例&&多例模式

        2.1 理论知识

        2.2 代码论证


一、bean生命周期的原理

1.1 了解bean的生命周期

首先我们就要思考一个问题,那就是:

Spring是管理项目中所有的javabean对象;

这些bean对象又是什么时候生?什么时候提供服务?什么时候销毁?

我们可以一起来看看这张bean的生命周期图: 运行逻辑是从下往上根据箭头来看的;

Spring之bean的生命周期_第1张图片 

我们一起来分析一下: 

第一步:

通过XML、Java annotation(注解)以及Java Configuration(配置类)

等方式加载Spring Bean;

第二步:

:解析Bean的定义。

在Spring容器启动过程中,会将Bean解析成Spring内部的BeanDefinition结构;

理解为:将spring.xml中的标签转换成BeanDefinition结构

有点类似于XML解析;

第三步: 

BeanDefinition:包含了很多属性和方法。

例如:id、class(类名)、scope、ref(依赖的bean)等等。

其实就是:

将bean(例如)的定义信息存储到这个对应BeanDefinition相应的属性中;

例如:

-----> BeanDefinition(id/class/scope)

 第四步: 

BeanFactoryPostProcessor:是Spring容器功能的扩展接口。

注释:

1)BeanFactoryPostProcessor在spring容器加载完BeanDefinition之后,

      在bean实例化之前执行的

2)对bean元数据(BeanDefinition)进行加工处理,

     也就是BeanDefinition属性填充、修改等操作

结论1:

当我们运行这行代码时:

ClassPathXmlApplicationContext context =

new ClassPathXmlApplicationContext("/spring-context.xml");

会对Spring的配置文件进行建模,然后把bean标签转成BeanDefinition这个类,

这个时候BeanDefinition里面还没有值。

所以它会在被实例化之前被进行加工处理。

  第五步: 

BeanFactory:bean工厂。它按照我们的要求生产我们需要的各种各样的bean。

解释案例:

例:
BeanFactory -> List
BeanDefinition(id/class/scope/init-method)

foreach(BeanDefinition bean : List){
   //根据class属性反射机制实例化对象
   //反射赋值设置属性
}

 第六步: 

Aware感知接口:在实际开发中,经常需要用到Spring容器本身的功能资源;

具体应用案例:

BeanNameAware、ApplicationContextAware等等

BeanDefinition 实现了 BeanNameAware、ApplicationContextAware

结论2:

就是Aware感知接口帮助我们自己写的 bean对象 去获取到 spring容器 内部 内置对象。

 第七步: 

BeanPostProcessor:后置处理器。

在Bean对象实例化和引入注入完毕后,

再显示调用初始化方法的前后添加自定义的逻辑。(类似于AOP的绕环通知)

然后就完成Bean的创建; 

 第八步: 

destory:销毁。

 简单点做个总结整个生命周期的流程:

①:通过三种方式(配置文件、注解、配置类)将bean标签转成BeanDefinition对象;

③:通过BeanFactoryPostProcessor类,可以在初始化之前修改属性值;

④ :BeanFactory类进行bean实例化,也就是生产javabean;

⑤:Aware感知接口,能够在拿到Spring上下文中内部的资源对象;

⑥:BeanPostProcessor后置处理器,相当于环绕通知。

最后就是创建Bean成功,destory进行销毁。


二、Spring的单例&&多例模式

        2.1 理论知识

        然而Spring的javaBean是分为两种的,一种是单例,一种是多例;

        我们在Spring配置文件中也是可以配置的: 

                scope="singleton"   ---> 代表单例

                scope="prototype"  ---> 代表多例

        不配置的话默认就是单例;

	
	

	
	

                2.1.1 两种模式有什么区别?

                        我们先来看看一段代码:

public static void main(String[] args) {	
		//实例化四个对象
		Person p1 = new Person();
		Person p2 = new Person();
		Person p3 = new Person();
		Person p4 = new Person();
		
        //依次打印
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);
		System.out.println(p4);
}

                打印结果:

                Spring之bean的生命周期_第2张图片 

                        我们由此思考一下: 

                        一个类如果被使用了一百次会创建多少个对象?

                如果这个项目一共有一万个类呢?        答:100w个对象

                        结论:创建了很多不必要的对象会极大的占用空间。

                所以我们就需要用到了单例模式:

package com.leaf.beanLife;

public class Demo1 {
	
	public static void main(String[] args) {
		
		//实例化
//		Person p1 = new Person();
//		Person p2 = new Person();
//		Person p3 = new Person();
//		Person p4 = new Person();
		
		Person p1 = Person.newInstance();
		Person p2 = Person.newInstance();
		Person p3 = Person.newInstance();
		Person p4 = Person.newInstance();
		
		System.out.println(p1);
		System.out.println(p2);
		System.out.println(p3);
		System.out.println(p4);
		
	}
	
}

/**
 * 实体类:人类 
 * @author Leaf
 *
 * 2022年8月9日 上午3:41:38
 */
class Person{
	
	//私有化构造方法,让其他地方不能创建;
	private Person() {
		
	}
	
	//封装私有化的这个类
	private final static Person p = new Person();
	
	//封装一个方法,返回私有化的该类;
	public static Person newInstance() {
		return p;
	}
	
}

通过我们私有化构造方法,修改部分代码用到了单例模式后,我们再次运行:

Spring之bean的生命周期_第3张图片

这样我们就算把一个类在一百个地方使用,使用的都是同一个对象;

再次思考:

整个项目一共有1w个类,Spring上下文需要创建多少个对象?

答:1w个对象

到这里我们也就明显知道单例模式与多例的区别了,

单例模式的优点:就是极大的节省了空间,省略了很多的没必要的对象创建。

所以Spring默认使用单例模式;

 但是,Spring之所以还提供了多例模式供我们选择,

原因呢就是:单例模式一样存在弊端!

例如:变量污染的问题;

生活中的案例:给孩子买玩具:

A:买2份玩具,两个孩子都开心,不会有矛盾。

B:买1份玩具,两个孩子可能会有争执;

轮流玩,孩子"小明"先玩了一上午后,孩子"小白"再去玩感觉就不一样了,

觉得污染了,染上了泥巴什么的,就会有争吵。

两种买玩具的方式有利有弊,

买两份呢:钱包有压力。买一份呢:兄弟容易打架。

结论:

A就相当于多例模式,B就相当于单例模式。

所以Spring就视情况而定,提供两种模式供我们按情况来选择。


        2.2 代码论证

        我们经过生活中的案例,已经把关于单例模式与多例模式的理论方面的理解 全部分析讲出来了,接着 我们就要用代码 实操 印证一下我们的结论了。

        首先我们准备一些测试的准备类:

        InstanceFactory:验证初始化javabean

package com.leaf.beanLife;

/**
 * 为了印证 BeanPostProcessor 初始化javabean对象
 * @author Leaf
 *
 * 2022年8月9日 上午5:06:39
 */
public class InstanceFactory {
	public void init() {
		System.out.println("初始化方法");
	}

	public void destroy() {
		System.out.println("销毁方法");
	}

	public void service() {
		System.out.println("业务方法");
	}
}

  ParamAction:验证单例模式与多例模式的区别

package com.leaf.beanLife;

import java.util.List;

import com.leaf.ioc.biz.UserBiz;
import impl.UserBizImpl1;
import impl.UserBizImpl2;

/**
 * 印证单例模式与多例模式的区别
 * @author Leaf
 *
 * 2022年8月9日 上午5:07:27
 */
public class ParamAction {
	
	private int age;
	private String name;
	private List hobby;
	private int num = 1;
	// private UserBiz userBiz = new UserBizImpl1();

	public ParamAction() {
		super();
	}

	public ParamAction(int age, String name, List hobby) {
		super();
		this.age = age;
		this.name = name;
		this.hobby = hobby;
	}

	public void execute() {
		// userBiz.upload();
		// userBiz = new UserBizImpl2();
		System.out.println("this.num=" + this.num++);
		System.out.println(this.name);
		System.out.println(this.age);
		System.out.println(this.hobby);
	}
}

  Demo2:测试类

package com.leaf.beanLife;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/*
 * 测试类
 * spring	bean的生命週期
 * spring	bean的單例多例
 */
public class Demo2 {
	// 体现单例与多例的区别
	@Test
	public void test1() {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
		ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");
		ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");
		// System.out.println(p1==p2);
		p1.execute();
		p2.execute();
		
//		单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;
		applicationContext.close();
	}

	// 体现单例与多例的初始化的时间点 instanceFactory
	@Test
	public void test2() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
	}

	// BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
	// 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
	@Test
	public void test3() {
		// ClassPathXmlApplicationContext applicationContext = new
		// ClassPathXmlApplicationContext("/spring-context.xml");

		Resource resource = new ClassPathResource("/spring-context.xml");
		BeanFactory beanFactory = new XmlBeanFactory(resource);
//		InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
		
	}

}

  spring-context.xml:Spring配置文件

    
	
		
		
		
			
				抽烟
				烫头
				大保健
			
		
	

	
	

  然后我们依次测试:

        ①:体现单例与多例的区别:

                下面这个就是相当于单例:

Spring之bean的生命周期_第4张图片

         然后我们改变一下配置:Spring之bean的生命周期_第5张图片

然后再来运行测试:Spring之bean的生命周期_第6张图片 

我们还要知道一个结论:

        单例模式:容器生对象生,容器死对象死。

        多例模式:使用时对象生,死亡跟着jvm垃圾回收机制走。

以上这些就是单例和多模式的区别啦。 

并且bean的初始化时间点,除了跟bean管理模式(单例&多例)有关之外;

还跟BeanFactory的子类有关。


OK,以上就是Leaf今天带来的关于Spring管理的javabean的生命周期以及他的两种模式的知识分享啦,我们下期再见啦!!!

你可能感兴趣的:(Spring,spring,java)