上一节中,我们深入了解了Spring中bean之间是如何进行关联的以及简单了解控制反转和依赖注入。这一节中,我们主要来说说bean。
一、从applicationContext应用上下文和bean工厂中获得bean有什么区别?
bean的作用域(4种)
singleton:在每个Spring IOC容器中一个bean定义对应一个对象实例。(只要容器存在,那么就只有一个bean。比如说
Student st1 =(Student) ac.getBean(“student”);
Student st2 =(Student) ac.getBean(“student”);
这样创建出的只是一个Student对象。)prototype:一个bean定义对应多个 (每获得一个bean就是一个全新的bean。比如说
Student st1 =(Student) ac.getBean(“student”);
Student st2 =(Student) ac.getBean(“student”);
这样创建出的却是两个不同的Student对象。))request:在一次http请求中,一个bean定义对应一个实例;即每次http请求将会有各自的bean实例,他们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。(一次请求有效)
global Session:在一个全局http Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web 的Spring applicationContext情形下有效。(只要Spring容器不关闭,那么他就一直有效)
创建bean的方式
- 利用ApplicationContext创建
当bean的scope是 singleton时,程序一旦执行
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
时,程序会自动加载Spring容器,并且将里面的bean实例化。 但是,当我们设置scope是prototype的时候,他依然是延时加载的。
利用bean工厂来创建
程序一旦执行BeanFactory factory = new XmlBeanFactory( new ClassPathResource("applicationContext.xml"));
时,程序只是对该容器进行实例化,并不会马上实例化容器中的bean,当我们使用getbean方法去得到某个bean时,才会实时创建出该对象。
从上面的描述中我们可以清楚地知道,利用ApplicationContext的方式(scope=”singleton”)获得bean可以增加程序的运行速度,因为他可以预先加载所有单例模式的bean,确保应用不需要等待他们被创建。利用bean工厂可以节省内存。
但是我们通常还是用ApplicationContext的方式来获得bean。
二、bean的生命周期
1. 实例化
当程序加载.xml文件的时候就开始实例化。把我们的bean(单态的)实例化到内存中(使用无参的构造函数来实例化)。
<bean id="userService" class="rogue.UserService" />
2. 设置属性
调用set方法设置属性
3. 如果实现了BeanNameAware接口并且实现了setBeanName()方法
public void SetName(Stirng arg0){}
该方法可以用arg0表示正在被实例化的bean的id(返回的值取决于你在配置文件中的id设置的是什么。)
4. 如果实现了BeanFactoryAware接口并且调用了setBeanFactory()方法
public void setBeanFactory(BeanFactory arg0) throws BeanException{}
该方法可以用arg0传递所使用的beanFactory对象
5. 如果实现了ApplicationContextAware接口并且调用了setApplicationContext()方法
public void setApplicationContext(ApplicationContext arg0) throws BeansException{}
那么可以通过arg0传递获取ApplicationContext的方式。(获取方式有三种,这里不细说,立一个flag)
6. 调用BeanPostProcessor(后置处理器)的预初始化方法(before)
这个处理器不是直接在该bean中实现的(也就是不能在bean中直接用implements),而是通过在.xml配置文件中配置来完成的。
如果实现了这个接口,则会自动调用Before方法。
使用方法如下:
a、首先创建一个类MyBeanPostProcessor,实现BeanPostProcessor接口
b、然后在MyBeanPostProcessor中的初始化方法
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException {
// TODO Auto-generated method stub
return null;
}
中写入自己的功能函数。这里的arg0指的就是调用这个方法的对象,return的时候要将其返回,而不能是空。
c、在xml文件中配置
<bean id="myBeanPostProcessor" class="rogue.MyBeanPostProcessor"/>
7. 如果实现了InitializingBean接口,则会调用afterPropertiesSet()方法。
public void afterPropertiesSet() throws Ecception{}
8. 自定义初始化方法
我们还可以在自己的bean中配置初始化方法,如果我们在bean中配置了这样的方法
<bean id="userService" init-method="init" class="rogue.UserService" />
这样,在自己UserService中添加一个
public void init(){}
方法,则他会在第七步(如果有的话)执行完之后被调用
9. 调用BeanPostProcessor(后置处理器)的预初始化方法(after)
public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException {
// TODO Auto-generated method stub
return null;
}
10、bean可以被使用
11、容器关闭
12、可以通过实现DisposableBean接口来调用方法destiny
13、容器销毁(我们可以关闭数据连接,socket,文件流,释放该bean占用的资源),也可以用自定义销毁方法来实现。如果没有,则程序自动销毁。
<bean id="userService" destroy-method="myDestroy" class="rogue.UserService" />
下面是执行的结果:
下面是bean执行顺序图
我们在实际开发中,往往用不到这么多的过程,常见的过程有:
1->2->6->9->10->11
三、利用BeanFactory来获取bean对象
以上是利用ApplicationContext来获取bean的过程,那么利用BeanFactory来获取bean对象是怎样的流程呢?
从运行结果中我们可以看出,运行的流程是这样的