bean配置有三种方法:
- 基于xml配置Bean
- 使用注解定义Bean
- 基于java类提供Bean定义信息
基于XML配置Bean
Bean 的作用域
当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 **prototype**
。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 **singleton**
。
Spring 框架支持以下五个作用域,分别为singleton
、prototype
、request
、session
和global session
,5种作用域说明如下所示:
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境 |
注意,如果你使用 web-aware ApplicationContext 时,其中后三个是可用的。
singleton 作用域
singleton
是默认的作用域,也就是说,当定义 Bean 时,如果没有指定作用域配置项,则 Bean 的作用域被默认为 singleton
。
当一个bean的作用域为Singleton
,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。也就是说,当将一个bean定义设置为singleton作用域的时候,Spring IoC容器只会创建该bean定义的唯一实例。
Singleton
是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton
作用域是Spring中的缺省作用域。你可以在 bean 的配置文件中设置作用域的属性为 singleton,如下所示:
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
<!-- collaborators and configuration for this bean go here -->
</bean>
prototype 作用域
当一个bean的作用域为Prototype
,表示一个bean定义对应多个对象实例。Prototype
作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype
是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。
根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
为了定义 prototype
作用域,你可以在 bean 的配置文件中设置作用域的属性为 prototype
,如下所示:
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
Bean 的生命周期
理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。
《Sping实战》提到的典型的声明周期过程:
- Spring对Bean进行实例化(相当于程序中的new Xx())
- Spring将值和Bean的引用注入进Bean对应的属性中
- 如果Bean实现了
BeanNameAware
接口,Spring将Bean的ID传递给setBeanName()
方法(实现BeanNameAware
主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的) - 如果Bean实现了
BeanFactoryAware
接口,Spring将调用setBeanDactory(BeanFactory bf)
方法并把BeanFactory
容器实例作为参数传入。(实现BeanFactoryAware
主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等) - 如果Bean实现了
ApplicationContextAwaer
接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)
方法,把bean所在的应用上下文作为参数传入。(作用与BeanFactory
类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext
方法时会把它自己作为setApplicationContext
的参数传入,而Spring容器在调用setBeanDactory
前需要程序员自己指定(注入)setBeanDactory
里的参数BeanFactory
) - 如果Bean实现了
BeanPostProcess
接口,Spring将调用它们的postProcessBeforeInitialization
(预初始化)方法。(作用是在Bean实例创建成功后进行增强处理,如对Bean进行修改,增加某个功能) - 如果Bean实现了
InitializingBean
接口,Spring将调用它们的afterPropertiesSet
方法,作用与在配置文件中对Bean使用init-method
声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。 - 如果Bean实现了
BeanPostProcess
接口,Spring将调用它们的postProcessAfterInitialization
(后初始化)方法。(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 ) - 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
- 如果Bean实现了
DispostbleBean
接口,Spring将调用它的destory
方法,作用与在配置文件中对Bean使用destory-method
属性的作用一样,都是在Bean实例销毁前执行的方法。
示例:
package com.haan.beanlifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @Desc
* @Created By liukuihan
* @date on 2020/5/23
*/
public class LiftCycleTest implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean,DisposableBean {
private String message;
public LiftCycleTest(){
System.out.println("实例化LiftCycleTest...");
}
public void setMessage(String message) {
this.message = message;
System.out.println("设置LiftCycleTest的message属性..."+message);
}
@Override
public void setBeanName(String s) {
System.out.println("Bean(LiftCycleTest)的bean Id="+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(beanFactory.toString());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(applicationContext.toString());
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean之前...");
return null;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean的全部属性设置成功...");
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化bean之后...");
return null;
}
@Override
public void destroy() throws Exception {
System.out.println("bean被摧毁了");
}
public void customerInit(){
System.out.println("定制初始化方法执行了...");
}
public void customerDestroy(){
System.out.println("定制bean摧毁方法执行了...");
}
}
bean.xml
<?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">
<bean class="com.haan.HelloWord" id="helloWord"></bean>
<bean class="com.haan.beanlifecycle.LiftCycleTest" id="liftCycleTest" init-method="customerInit" destroy-method="customerDestroy">
<property name="message" value="testssssssss"/>
</bean>
</beans>
main
public class Main {
public static void main(String[] args) {
// BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("bean.xml")); //<1>
//
// HelloWord helloWord = (HelloWord) beanFactory.getBean("helloWord"); //<2>
// helloWord.sayHello(); //<3>
//
// ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// HelloWord helloWord = (HelloWord) context.getBean("helloWord");
// helloWord.sayHello();
AbstractApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
context.registerShutdownHook();
}
}
实例化LiftCycleTest...
设置LiftCycleTest的message属性...testssssssss
Bean(LiftCycleTest)的bean Id=liftCycleTest
org.springframework.beans.factory.support.DefaultListableBeanFactory@4cb2c100: defining beans [helloWord,liftCycleTest]; root of factory hierarchy
org.springframework.context.support.ClassPathXmlApplicationContext@1a86f2f1, started on Sat May 23 11:33:23 CST 2020
Bean的全部属性设置成功...
定制初始化方法执行了...
初始化bean之前...
初始化bean之后...
bean被摧毁了
定制bean摧毁方法执行了...