在Spring容器中Bean的作用域分为singleton、prototype。对于这两种Bean的作用域简单谈一下个人的认识,singleton的对象为单例模式,这样的对象在Spring的容器中只维持一个,需要的时候可以来取,也就是说这个对象将自己的控制权交给了Spring容器,那么他什么时候创建(单例的对象在加载配置文件的时候创建)与销毁取决于Spring容器而不是取决于Bean类本身。而prototype类型的对象,并不是完全交给Spring容器进行管理的,创建的时候需要Spring容器进行创建,但是销毁的时候并不取决于Spring容器,取决于客户端,当客户端访问的时候由Spring创建对象,客户端访问完成后,Bean对象处于未引用的状态下,就会被JVM自动回收。
Spring创建Bean执行顺序
说明下:Bean在Spring容器创建完成之后如果还希望调用其他的方法完成某些必要的动作的方式应该是有两种方式,包括下面要讲到的initMethod配置指定执行方法,以及实现InitializingBean接口中的afterPropertiesSet()方法。
比较而言,我更喜欢用initMethod配置的方式,这样的话,可以实现类与类之间的解耦,而实现InitializingBean接口的方式显然会发生耦合,这里我只阐述一下第一种方式(结合前面几篇博文中的例子进行理解)。
希望大家通过这下面的例子,可以体会到,Spring进行创建Bean的时候的顺序,这样有利于某些特殊情形下的控制。
这里是一个实体类
package com.siti.spring20160309bean;
public class WY {
private String userName;
public WY(){
System.out.println("WY构造函数!");
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
这里的BeanNameAware和ApplicationContextAware接口在之前的博文中已经作了阐述与实例,这里只做简要的说明:BeanNameAware接口中setBeanName方法,在实例化该Bean的时候会将其id注入进来,在某些特殊情形下会用得到的。ApplicationContextAware接口的setApplicationContext()方法会在实例化Bean的时候将当前的Spring容器直接注入进来。
package com.siti.spring20160309bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class WangYang implements BeanNameAware, ApplicationContextAware{
private WY wy;
public void setWy(WY wy) {
this.wy = wy;
System.out.println("为wy注入对象!");
}
public WangYang(){
System.out.println("WangYang构造函数!");
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
System.out.println("context!");
}
@Override
public void setBeanName(String beanId) {
System.out.println("beanId!" + beanId);
}
public void init(){
System.out.println("完成部分必要动作!");
}
}
那么通过配置文件对这两个Bean进行配置。
<?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 name = "wy" class = "com.siti.spring20160309bean.WY"></bean>
<bean name = "wangyang" class = "com.siti.spring20160309bean.WangYang" init-method="init">
<property name="wy" ref="wy"></property>
</bean>
</beans>
测试类只需要加载配置文件即可
<span style="font-size:14px;">ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext20160309.xml");</span>
运行结果如下:
可以看到,当这个Bean有依赖的Bean的时候需要先创建其依赖的Bean,然后调用该Bean的构造函数创建实例对象,将依赖的Bean注入进来,接下来会得到当前实例化的Bean的id,接着可以得到他当前的容器ApplicationContext对象,然后是你设置的initMethod方法,这个方法在实体创建好之后可以完成一些必要的动作。
销毁Bean的执行顺序
说明下:同样的和创建bean的时候类似,在销毁Bean之前执行一些自定义的任务也有两种方式,可以通过配置destroy-method来设置调用的方法。另一种方式是实现DisposableBean类中的destroy()方法。我这里同样只展示下,destroy-method方法。
在WangYang类中加一个方法
public void destroyMethod(){
System.out.println("销毁Bean前调用方法!");
}
配置文件中在后面添加上destroy-method
<bean name = "wangyang" class = "com.siti.spring20160309bean.WangYang" init-method="init" destroy-method="destroyMethod">
<property name="wy" ref="wy"></property>
</bean>
测试类中
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext20160309.xml");
context.registerShutdownHook();
这里说明下,registerShutdownHook方法是在JVM中注册一个关闭的钩子,保证Spring容器被恰当的关闭,且自动执行singleton Bean实例的析构回调方法。
大致流程如图所示: