Bean的作用域与生命周期

Bean的作用域

以Spring4.3为例,其中为Bean的实例化定义了7种作用域分别为:
1.singleton(单例):使用singleton定义的Bean在Spring容器中将只有一个实例,也就是说,无论有多少个Bean引用它,始终将指向同一个对象。这也是Spring容器默认的作用域
2.prototype(原型):每次通过Spring容器获取的prototype定义的Bean时,容器都将创建一个新的Bean实例。
3.request:在一次HTTP请求中,容器会返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean。而且该Bean仅在当前HTTP Request内有效。
4.session:在一次HTTP Session中,容器会返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Session内有效。
5.globalSession:在一个全局的HTTP Session中,容器会返回该Bean的同一个实例。仅在使用portlet上下文时有效。
6.application:为每个ServletContext对象创建一个实例。仅在Web相关的ApplicationContext中生效。
7.websocket:为每个websocket对象创建一个实例。仅在Web相关的ApplicationContext中生效。

这7中作用域中最为常用的就是singleton(单例)和prototype(原型) 两种作用域,根据这两种最为常用的作用域,编写简单程序来具体了解一下他们的效果和区别。

singleton作用域

singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会存在一个共享的Bean实例。singleton作用域的Bean对于无会话状态的Bean(如Dao组件,Service组件)来说,是最理想的选择。

首先在src目录下创建一个包,在包中创建一个类命名为Scope,使用构造器实例化方法来实例它,也就是调用它的默认无参构造方法来完成实例化。再创建一个配置文件,在其中加入bean子元素,将其id值设置为scope其class属性设置为Scope类的全限定名,并加入新属性scope,将其属性值设为singleton。完成配置。

<?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/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<bean id="scope" class="beginner.scope.Scope" scope="singleton" />
</beans>

创建测试类,在测试类中编写一个main方法,依旧是先定义配置文件的路径,然后加载配置文件,最后输出获得的实例对象,代码如下:

package beginner.scope;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SingletonText {

	public static void main(String[] args) {
		// 定义配置文件路径
		String xmlPath = "beginner/scope/Scope.xml";
		// 加载配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		// 输出获得的实例
		System.out.println(applicationContext.getBean("scope"));
		System.out.println(applicationContext.getBean("scope"));

	}

}

小技巧,Ctrl+Alt+下方向键可以直接复制一行代码。
通过执行结果可以发现,获得的两个实例对象是完全相同的,也就是同一个实例对象。符合singleton作用域的描述。
在这里插入图片描述

prototype作用域

prototype作用域对于需要保持会话状态的Bean(如Struts2的Action类)应该使用prototype作用域。在使用prototype作用域时,Spring容器会为每个对该Bean的请求都创建一个新的实例。

对于prototype作用域的实验可以在singleton的代码基础上稍作修改就可以完成。首先,在配置文件中,使用小技巧复制一行bean子元素的代码,将原本的注释掉,将新的bean子元素的id属性设置为scope1(可以不改,此处只是为了稍作区分),scope属性设置为prototype即可。

<?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/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

	<!--  <bean id="scope" class="beginner.scope.Scope" scope="singleton" />  -->
	<bean id="scope1" class="beginner.scope.Scope" scope="prototype" />
</beans>

将测试类代码中,输出语句中applicationContext.getBean(“scope”);scope相应修改为scope1即可。

package beginner.scope;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SingletonText {

	public static void main(String[] args) {
		// 定义配置文件路径
		String xmlPath = "beginner/scope/Scope.xml";
		// 加载配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		// 输出获得的实例
		System.out.println(applicationContext.getBean("scope1"));
		System.out.println(applicationContext.getBean("scope1"));

	}

}

在执行结果可以看到,虽然输出的两个实例对象都为scope1对象,但是地址却不同,说明这是两个不同的实例对象,符合prototype作用域的描述,每次都返回一个新的实例。
在这里插入图片描述

Bean的生命周期

了解Spring中Bean的声明周期的意义在于,可以利用Bean在其存活期间的特定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,常会在Bean的postinitiation(初始化后,如传递参数)predestruction(销毁前,如关闭资源) 执行一些相关操作。

Spring容器可以管理Bean的某一部分作用域的生命周期。

singletonprototype
在singleton作用域中Spring可以全程的跟踪,在此作用域下,Spring能够精确的知道该Bean何时被创建,何时实例化完成以及何时被销毁。如果作用域是prototype的情况下,Spring只负责创建,当容器创建完成Bean实例后,Bean的实例就交给客户端代码来管理,Spring容器将不再跟踪其生命周期

Spring容器中Bean的详细生命周期流程图:

1.实例化Bean。
2.设置属性值,利用依赖注入,完成Bean里属性的注入。
3.(当Bean对象实现BeanNameAware(接口) 时)调用BeanNameAware(接口)setBeanName() 方法。
4.(当Bean对象实现BeanFactoryAware(接口) 时)调用BeanFactoryAware(接口)setBeanFactory() 方法。
5.(当Bean对象实现ApplicationContextAware(接口) 时)调用 ApplicationContextAware(接口)setApplicationContext() 方法。
6.调用BeanPostProcessor 的预初始化方法(在自定义初始化方法之前执行)。
7.调用InitializingBeanafterPropertiesSet() 方法。
8.调用定制的初始化方法(自定义的初始化方法)。

9.调用BeanPostProcessor的初始化方法
10.在singleton作用域下 Spring缓冲池中准备就绪的Bean或者
10.prototype作用域下 将准备就绪的Bean交给调用者
11.调用Disposable的destory方法或者调用destory-method属性配置的销毁方法

演示singleton作用域中Bean的声明周期。

首先在src目录下新建一个包,在包下新建一个类命名为life,使用构造器实例化方法完成实例化,在默认的无参构造方法中加入一条输出语句,输出:实例化完成,再在其中定义一个初始化方法和销毁方法,分别输出语句初始化完成和销毁完成。具体代码如下:

package beginner.life;

public class Life {

	private Life() {
		// 构造方法
		System.out.println("实例化完成");
	}

	public void initMethod() {
		// 初始化方法
		System.out.println("初始化完成");
	}

	public void destroyMethod() {
		// 销毁方法
		System.out.println("销魂完成");
	}
}

接下来编写配置文件,定义其id和class属性,设置init-method 属性为类中定义的初始化方法名称,destroy-method 属性定义为类中定义的销毁方法名称。由于scope属性默认值即为singleton,所以可以不手动编写。

<?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/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">


	<bean id="life" class="beginner.life.Life"
		init-method="initMethod" destroy-method="destroyMethod" />


</beans>

编写测试类,依旧先定义配置文件路径,不过这次使用ClassPathXmlApplicationContext 因为ClassPathXmlApplicationContext 提供了关闭容器的方法,这样Bean的销毁方法才会被调用。最后关闭容器。具体代码如下:

package beginner.life;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LifeTest {
	public static void main(String[] args) {
		// 定义配置文件路径
		String xmlPath = "beginner/life/Life.xml";
		// ClassPathXmlApplicationContext在加载配置文件时对Bean进行实例化
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
		// ClassPathXmlApplicationContext 提供了关闭容器的方法,这样Bean的销毁方法才会被调用
		context.close();
	}

}

在这里插入图片描述
可以由执行结果看到在singleton作用域下Bean的生命周期流程为:
1.实例化
2.初始化
3.销毁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值