Spring中bean的作用域与生命周期——最详细讲解

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

Spring中的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢?
常用解决方式:1.单例改为多例;2.加锁,时间换空间;3.使用ThreadLocal,空间换时间。

一、 bean的作用域

Spring 有五种作用域:singleton、prototype、request、session、global session。

1.singleton——唯一 bean 实例
默认的作用域 spring IOC容器仅存在一个Bean实例,Bean以单例方式存在,在创建起容器时就同时自动创建了一个bean的对象。

2.prototype——每次请求都会创建一个新的 bean 实例
在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的getBean() 方法)时都会创建一个新的 bean 实例,相当于执行newXxxBean()。
prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

3.request——每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
request只适用于Web程序,每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,当请求结束后,该对象的生命周期即告结束。

4.session——每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
session只适用于Web程序,session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean,同时该 bean 仅在当前 HTTP session 内有效。

5.globalSession——一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境。

二 、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的生命周期是这样:bean的实例化–>bean的初始化–>bean的使用–>bean的销毁。
bean的创建:
1)从xml配置的Bean,@Bean注解,或者Java代码BeanDefinitionBuilder中读取Bean的定义,实例化Bean对象;

2)设置Bean的属性;

3)注入Aware的依赖(BeanNameAware,BeanFactoryAware,ApplicationContextAware…)

4)执行通用的方法前置处理,方法:BeanPostProcessor.postProcessorBeforeInitialization()

5)执行@PostConstruct 注解标注的方法

6)执行 InitalizingBean.afterPropertiesSet() 方法

7)执行Bean自定义的初始化方法init ;

8)执行方法BeanPostProcessor.postProcessorAfterInitialization()

9)创建对象完毕;

bean的销毁:

10)执行 @PreDestory 注解标注的方法;

11)执行 DisposableBean.destory() 方法;

12)执行自定义的destory方法;

13)销毁对象完毕

其中,3、4、5、6、7、8、10、11、12只是可能发生的事情。

三 、Spring在Bean从创建到销毁的生命周期中可能做的事情。

initialization 和 destroy

1.实现InitializingBean和DisposableBean接口(第6、11步)

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

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

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

2.在bean的配置文件中指定init-method和destroy-method方法(第7、12步)

自定义 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注解(第5、10步)

Spring 也支持用 @PostConstruct@PreDestroy 注解来指定 init 和destroy 方法。这两个注解均在 javax.annotation 包中。

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

BeanPostProcessor

Spring同样可以针对容器中的所有Bean,或者某些Bean定制初始化过程,只需提供一个实现
BeanPostProcessor接口的类即可。

该接口中包含两个方法:
postProcessBeforeInitializationpostProcessAfterInitialization。(第4、8步)

postProcessBeforeInitialization方法会在容器中的Bean初始化之前执行, postProcessAfterInitialization方法在容器中的Bean初始化之后执行

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

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

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

这些接口均继承于 org.springframework.beans.factory.Aware 标记接口,并提供一个将由 Bean
实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用

一些重要的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{
	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println("执行setBeanClassLoader,ClassLoader Name = " +
		classLoader.getClass().getName());
	} 
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("执行setBeanFactory,setBeanFactory:: giraffe bean
		singleton=" + beanFactory.isSingleton("giraffeService"));
	} 
	@Override
	public void setBeanName(String s) {
		System.out.println("执行setBeanName:: Bean Name defined in context="
		+ s);
	} 
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
	throws BeansException {
		System.out.println("执行setApplicationContext:: Bean Definition Names="
		+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
	} 
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher
	applicationEventPublisher) {
		System.out.println("执行setApplicationEventPublisher");
	} 
	@Override
	public void setEnvironment(Environment environment) {
		System.out.println("执行setEnvironment");
	} 
	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		Resource resource = resourceLoader.getResource("classpath:springbeans.xml");
		System.out.println("执行setResourceLoader:: Resource File Name="
		+ resource.getFilename());
	} 
	@Override
	public void setImportMetadata(AnnotationMetadata annotationMetadata) {
		System.out.println("执行setImportMetadata");
	}
}

如果对你有帮助的话,请点赞收藏!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值