1.背景
在 自定义Bean里 可以设置创建 bean 实例是单实例还是多实例的,默认情况下, bean 是单实例对象。
例如:
@Test
public void testBean2() {
//1 加载spring配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
//2 获取配置创建的对象
Emp emp = context.getBean("emp", Emp.class);
Emp emp1 = context.getBean("emp", Emp.class);
System.out.println(emp);
System.out.println(emp1);
}
打印结果是:
com.liuqingchao.spring5.Emp@c8211c
com.liuqingchao.spring5.Emp@c8211c
设置方法:
(1)在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例。
例如上面的配置改成:
<bean id="emp" class="com.liuqingchao.spring5.Emp" scope="prototype">
此时就可以看到两个bean不一样。
singleton 和 prototype 区别
第一 singleton 单实例, prototype 多实例
第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用
getBean 方法时候创建多实例对象。
2.bean 生命周期
任何 IOC容器(包括 Spring 在内)的一个重要内容是构建 bean,并可以在生命周期中的某些点接收通知。这样就能够在 bean 的整个生命周期中的某些点上完成相关处理。 通常,有两个生命周期事件与 bean特别相关 : post-initialization 和 pre-destruction。在 Spring 的上下文中, 一旦 Spring 完成 bean 的所有属性值设置以及所配置的依赖项检查,就会触发post-initialization 事件。在 Spring 销毁 bean 实例之前,pre-destruction 事件被触发。但是,对于具有原型作用域的 bean来说, Spring 并不会触发 pre-destruction 事件。 Spring的设计思想是,不管 bean 的作用域如何,初始化生命周期回调方法将在对象上被调用,而对于具有原型作用域的 b酬,销毁生命周期回调方法则不会被调用。 bean 可以使用Spring 提供的三种机制挂钩到每个事件中并执行一些额外的处理,分别是基于接口的、基于方法的和基于注解的
机制 。
如果使用基于接口的机制,那么 bean 需要实现一个特定于想要接收的通知类型的接口,并且 Spring 通过接口中定义的回调方法来通知 bean 。 如果使用基于方法的机制, Spring 允许在 ApplicationContext 配置中指定在初始化bean 时要调用的方法名以及在销毁 bean 时要调用的方法名。如果使用基于注解的机制, 则可以使用 JSR-250 注解来指定 Spring 在构建之后或销毁之前要调用的方法。在你自己的 bean 中,使用基于方法或基于注解的机制可能会更好,因为bean 不需要实现任何 Spr ing 特定的接口。
这张图概括了Bean的主要生命周期:
我们可以清晰地看到Spring Bean的生命周期可以分为四个阶段
第一个阶段是IOC过程扫描到bean,创建,并为其属性赋值。
第二个阶段是如果类实现了**Aware接口,BeanNameAware,BeanClassLoaderAware,ApplicationContextAware接口的话,会调用相关的set方法来执行。这几个Aware是干什么用的呢?后面小节单独讨论。
第三个阶段是创建Bean,主要是执行了构造方法之后,如果定存在注解@PostConstruct,InitializingBean或者通过init-method指定了初始化方法时,继续完成相关的初始化工作。
第四个是调用结束,销毁之前,基本是第三阶段的反过程,如果存在注解@PreDestroy,实现了DisposableBean或者通过destroy-method指定了销毁方法,则先执行这些方法,最后进行销毁。
3.Aware接口的作用
在生命周期里第二项,如果实现了**Aware接口,例如BeanNameAware,BeanClassLoaderAware,ApplicationContextAware接口的话,会调用相关的set方法来执行。这些Aware到底是干什么的呢?
Aware的提供是为了我们能够使用Spring内部提供的一些接口或者类的功能。我们以ApplicationContextAware为例,如果我们想要使用ApplicationContext我们可以在定义的类实现ApplicationContextAware接口,代码如下:
@Component
public class ApplicationContextAwareBean implements ApplicationContextAware {
//ApplicationContext实例会在ApplicationContextAwareBean 实例化时通过
//下面的setApplicationContext方法赋值
//我们在该类可以使用ApplicationContext实例提供的任何功能
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
也就是说我们实现了谁的aware就可以将谁当做属性直接使用了。
除了ApplicationContextAware,我们还可以实现ApplicationEventPublisherAware接口,该接口会设置ApplicationEventPublisher 实例,我们可以通过ApplicationEventPublisher 实例发布事件。
常见的Aware有: