在 Spring 中,那些组成应用程序的主体及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IOC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。
Spring中的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢?
常用解决方式:1.单例改为多例;2.加锁,时间换空间;3.使用ThreadLocal,空间换时间。
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环境。
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只是可能发生的事情。
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 {
//通过的destroy-method属性指定的销毁方法
public void destroyMethod() throws Exception {
System.out.println("执行配置的destroy-method");
}
//通过的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注解标注的方法");
}
}
Spring同样可以针对容器中的所有Bean,或者某些Bean定制初始化过程,只需提供一个实现
BeanPostProcessor接口的类即可。
该接口中包含两个方法:
postProcessBeforeInitialization和postProcessAfterInitialization。(第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;
}
}
有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取ServletContext 的一些参数,获取 ApplicaitionContext 中的 BeanDefinition 的名字,获取 Bean 在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware的接口。
这些接口均继承于 org.springframework.beans.factory.Aware 标记接口,并提供一个将由 Bean
实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用。
一些重要的Aware接口:
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");
}
}
如果对你有帮助的话,请点赞收藏!