文档章节

浅析 Spring IoC - Bean Scopes 和 生命周期

pradosoul
 pradosoul
发布于 2015/10/21 17:37
字数 2117
阅读 326
收藏 8
点赞 0
评论 0

1. Bean scopes

    Scope用来声明 IoC 容器中对象应该处的限定场景或者说该对象的存活空间,即 IoC 容器在对象进入相应的 scope 之前生成并装配这些对象,在该对象不再处于 scope 的限定后,容器通常会销毁这些对象。下面是 Scope的分类:

Scope Description
singleton

(Default) Scopes a single bean definition to a single object instance per 

Spring IoC container.

prototype Scopes a single bean definition to any number of object instances.
request

Scopes a single bean definition to the lifecycle of a single HTTP request;

 that is, each HTTP request has its own instance of a bean created off the 

back of a single bean definition. Only valid in the context of a web-aware 

Spring ApplicationContext.

session

Scopes a single bean definition to the lifecycle of an HTTP Session.

 Only valid in the context of a web-aware Spring ApplicationContext.

global 

session

Scopes a single bean definition to the lifecycle of a global HTTP Session

Typically only valid when used in a portlet context. Only valid in the context 

of a web-aware Spring ApplicationContext.

application

Scopes a single bean definition to the lifecycle of a ServletContext. Only valid

 in the context of a web-aware Spring ApplicationContext.

    singleton:单一实例,即一个容器中只存在一个这样的实例,所有对该类型 Bean的依赖都是用这一单一实例。此外,singleton 类型的 Bean 定义,从容器启动,到它第一次被请求而实例化开始,只要容器不销毁或者退出,该类型 Bean 的单一实例就会一直存活。

    prototype:容器在接受到该类型对象的请求时,每次都会重新生成一个新的对象给请求方。但容器将对象实例返回给请求方后,就不再拥有该对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作。

    request、session、global session、application 只适用于 web程序,通常是和 XmlWebApplicationContext 共同使用。

    request:Spring 容器,即 XmlWebApplicationContext 会为每个 HTTP 请求创建一个新的对象,当请求结束后,该对象的生命周期即结束。如果同时又10个 HTTP 请求,容器会分别针对这10个请求创建10个新的对象实例,且实例之间互不干扰。

    session:Spring 容器会为每个独立的 session 创建新的对象实例,比 request scope的 bean存活更长的时间。用户登录信息一般是用的最多。

    global session:只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。

    application:暂无。

    对于singleton 和 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.xsd">

	<!-- <import resource="beans2.xml"/> -->

    <bean id="userDAO" class="com.dao.impl.UserDAOImpl" scope="singleton"/>
    
    <bean id="userService" class="com.service.impl.UserServiceImpl" scope="prototype">
        <property name="userDAO" ref="userDAO" />
    </bean>
    
</beans>

    测试 Code:

public class UserServiceTest {

	@Before
	public void setUp() throws Exception {
	}

	@Test
	public void testAddUser() throws Exception {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		
		UserDAOImpl dao1 = (UserDAOImpl) ctx.getBean("userDAO");
		UserDAOImpl dao2 = (UserDAOImpl) ctx.getBean("userDAO");
		
		UserServiceImpl service = (UserServiceImpl) ctx.getBean("userService");
		UserServiceImpl service2 = (UserServiceImpl) ctx.getBean("userService");
		
		System.out.println(dao1 == dao2);
		
		System.out.println(service == service2);
	}
}

    结果: true  false

2. Bean 创建的时机:

    IoC 容器初始化时会预先对非延迟加载的单例对象进行初始化,其他都是在第一次调用 getBean 时被创建。

    org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons()

public void preInstantiateSingletons() throws BeansException {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						@Override
						public Object run() {
							smartSingleton.afterSingletonsInstantiated();
							return null;
						}
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

3. 延迟初始化 Bean

    指在 IoC 容器启动时,并不初始化 延迟初始化的 Bean,而是在使用时才会创建以及初始化 Bean。

    配置方式:在 <bean> 标签上指定 lazy-init 属性值为 "true",如: <bean id="xxx" class="xxx" lazy-init="true" />

    Spring 容器预先初始化 Bean 通常能帮助我们提前发现配置错误,所以一般情况下不建议开启lazy-init。除非有某个 Bean 可能需要加载很大资源,而且在整个应用程序生命周期中很可能使用不到,那么可以设置为 延迟初始化。

    延迟初始化的 Bean 通常会在第一次使用时被初始化;或者在 被非延迟初始化 Bean 作为依赖对象注入时,随着该 Bean 的初始化而初始化 lazy-init Bean。

4. 自动装配(Autowire)

    Autowire 指由 spring 容器自动地注入依赖对象。

Mode Explanation
no

(Default) No autowiring. Bean references must be defined via a ref element. 

Changing the default setting is not recommended for larger deployments, 

because specifying collaborators explicitly gives greater control and clarity. 

To some extent, it documents the structure of a system.

byName

Autowiring by property name. Spring looks for a bean with the same name

 as the property that needs to be autowired. For example, if a bean definition 

is set to autowire by name, and it contains a master property (that is, it has a 

setMaster(..) method), Spring looks for a bean definition named master

and uses it to set the property.

byType

Allows a property to be autowired if exactly one bean of the property type

 exists in the container. If more than one exists, a fatal exception is thrown, 

which indicates that you may not use byType autowiring for that bean. 

If there are no matching beans, nothing happens; the property is not set.

constructor

Analogous to byType, but applies to constructor arguments. If there is not

 exactly one bean of the constructor argument type in the container, a fatal error is raised.

    目前 Spring 4.2.2 支持 "no","byName","byType","constructor" 四种自动装配,默认是 "no" 指不支持自动装配的。其中Spring 3.0 开始已经不推荐使用之前版本的 "autodetect" 自动装配,推荐使用 Java 5+支持的(@Autowired)注解方式代替;自动装配的好处是:减少构造器注入和setter注入配置,减少配置文件。

    配置方式:通过配置<bean>标签的“autowire”属性来改变自动装配方式

<bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byType">
    <!-- <property name="userDAO" ref="userDAO" /> -->
</bean>

    (1)default:表示使用默认的自动装配,默认的自动装配需要在<beans>标签中使用default-autowire属性指定,其支持“no”、“byName ”、“byType”、“constructor”四种自动装配。

<?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.xsd"
        default-autowire="byName">

    (2)no:意思是不支持自动装配,必须明确指定依赖。

    (3)byName:通过设置Bean定义属性autowire="byName",意思是根据名字进行自动装配,只能用于setter注入。

<?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.xsd">

	<!-- <import resource="beans2.xml"/> -->

    <bean id="userDAO" class="com.dao.impl.UserDAOImpl" >
    	<property name="daoId" value="1"></property>
    </bean>
    
    <bean id="userDAO2" class="com.dao.impl.UserDAOImpl" >
    	<property name="daoId" value="2"></property>
    </bean>
    
    <bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byName">
        <!-- <property name="userDAO" ref="userDAO" /> -->
    </bean>
    
</beans>
public class UserServiceImpl implements UserService {

	private UserDAO userDAO;
	
	public UserDAO getUserDAO() {
		return userDAO;
	}
	
	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}

	//constructor
//	public UserServiceImpl(UserDAO userDAO) {
//		super();
//		this.userDAO = userDAO;
//	}

	@Override
	public void addUser(User user) {
		this.userDAO.saveUser(user);
	}
}

    根据 byName 自动装配会去找 UserServiceImpl 中的 userDAO 这个name的 Bean,而配置文件中有 userDAO 和 userDAO2 两个,其中装配的是 userDAO。如果 userDAO 这个 Bean没有配置,则会报错。

    (4)byType:通过设置Bean定义属性autowire="byType",意思是指根据类型注入,用于setter注入。比如如果指定自动装配方式为“byType”,而 setUserDAO() 方法需要注入 UserDAO 类型数据,则Spring容器将查找 UserDAO 类Bean,如果找到一个则注入该Bean,如果找不到将什么也不注入;如果找到多个Bean将优先注入<bean>标签“primary”属性为 true 的 Bean,否则抛出异常来表明有个多个Bean发现但不知道使用哪个。

    (5)constructor:通过设置 Bean 定义属性autowire="constructor",功能和“byType”功能一样,根据类型注入构造器参数,只是用于构造器注入方式。

5. init-method 和 destroy-method

    (1)init-method="init" :指定初始化方法,在构造器注入和setter注入完毕后执行。

    (2)destroy-method="destroy":指定销毁方法,只有“singleton”作用域能销毁;“prototype”作用域的一定不能,因为容器不会监控 prototype Bean的死亡,推荐不要和 prototype 一起使用;其他作用域不一定能;

<bean id="userService" class="com.service.impl.UserServiceImpl" autowire="byName" 
    init-method="init" destroy-method="destroy">
    <!-- <property name="userDAO" ref="userDAO" /> -->
</bean>


© 著作权归作者所有

共有 人打赏支持
pradosoul
粉丝 6
博文 40
码字总数 37445
作品 0
闵行
程序员
《Spring Recipes》第二章笔记:Setting Bean Scopes

《Spring Recipes》第二章笔记:Setting Bean Scopes 问题 Spring容器默认创建的bean都是单例。 解决方案 Spring容器的<bean>元素的scope属性指定了bean的scope。 Table 4.3. Bean scopes 例...

LiJIaming
2012/05/17
0
0
《Spring Recipes》第一章笔记:Scanning Components from ...

问题 当需要注入的bean太多时,手工进行配置太费时费力,Spring容器提供了指定扫描功能。 解决方案 使用Spring的component scanning功能。可以通过@Component,@Repository, @Service , 和@...

LiJIaming
2012/05/15
0
0
9.01-Spring IOC 容器中Bean的生命周期

Spring IOC 容器可以管理Bean的生命周期,Spring 允许在Bean的生命周期的特定点执行定制的任务。 Spring IOC 容器中 Bean 的生命周期如下: ① . 通过构造器或工厂方法创建 Bean 实例 : 调用...

静以修身2025
06/27
0
0
Spring框架参考手册_5.0.0_中英文对照版_Part II_3.5

文章作者:Tyan 博客:noahsnail.com 3.5 Bean scopes When you create a bean definition, you create a recipe for creating actual instances of the class defined by that bean defini......

Quincuntial
2016/10/05
0
0
第2章:spring 依赖

第2章:spring 依赖 标签(空格分隔): JavaEE开发的颠覆者SpringBoot实战 spring中声明Bean的属性和构造函数参数有两种方法: 元素 元素 另外在声明具体的值上,我们可以是 Straight value...

超级个体颛顼
2017/11/09
0
0
Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y
05/22
0
0
Spring Boot Bean生命周期

注:Spring Boot Bean的生命周期,什么是Bean的生命周期,就是Bean从创建到销毁的过程。 Bean的生命周期过程描述 我们先看一下Bean的生命周期过程中都会经历些什么,我先简单解释一下,后面我...

爱编程的帅小伙
07/12
0
0
Spring Bean Scope

Spring Bean Scope 简单的解释一下bean 的scope singleton 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义...

秋风醉了
2014/11/26
0
0
Spring核心——Bean的定义与控制

在前面两篇介绍Sring核心与设计模式的文章中,分别介绍了Ioc容器和Bean的依赖关系。如果阅读过前2文就会知道,Spring的整个运转机制就是围绕着IoC容器以及Bean展开的。IoC就是一个篮子,所有...

随风溜达的向日葵
06/28
0
0
详解Spring中bean的scope

1、singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换...

姚君
2014/03/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

微信小程序Java登录流程(ssm实现具体功能和加解密隐私信息问题解决方案)

文章有不当之处,欢迎指正,如果喜欢微信阅读,你也可以关注我的微信公众号:好好学java,获取优质学习资源。 一、登录流程图 二、小程序客户端 doLogin:function(callback = () =>{}){let ...

公众号_好好学java
39分钟前
0
1
流利阅读笔记28-20180717待学习

“我不干了!” 英国脱欧大臣递交辞呈 雪梨 2018-07-17 1.今日导读 7 月 6 日,英国政府高官齐聚英国首相的官方乡间别墅——契克斯庄园,讨论起草了一份关于英国政府脱欧立场的白皮书。可是没...

aibinxiao
今天
7
0
OSChina 周二乱弹 —— 理解超算排名这个事,竟然超出了很多人的智商

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @-冰冰棒- :分享Ed Sheeran/Beyoncé的单曲《Perfect Duet (with Beyoncé)》 《Perfect Duet (with Beyoncé)》- Ed Sheeran/Beyoncé 手机...

小小编辑
今天
180
7
Android 获取各大音乐平台的真实下载地址

废话 电脑使用谷歌浏览器或者QQ浏览器的时候。。。。。。。说不清楚,还是看图吧 大概意思就是,只要网页上需要播放,只要能播放并且开始播放,这个过程就肯定会请求到相关的音乐资源,然后就...

她叫我小渝
今天
0
0
shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
今天
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
1
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部