Spring Bean 可以定义scope属性,指定创建对象的作用域,
默认是singleton,每一个Spring IOC 容器使用的都是同一个单一实例(单例模式),
prototype,将单一的Bean定义在任意数量的对象实例,
request,session,global-session只在 web-aware Spring ApplicationContext 的上下文中有效。
例子
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
<bean id="helloWorld" class="com.yzx.spring.test.Helloworld" scope="singleton">
</bean>
@Test
public void testHelloworld(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Helloworld helloworld = (Helloworld) applicationContext.getBean("helloWorld");
helloworld.setMsg("爱你");
System.out.println(helloworld.getMsg());
Helloworld helloworld2 = (Helloworld) applicationContext.getBean("helloWorld");
// helloworld2.setMsg("wo爱你");
System.out.println(helloworld2.getMsg());
}
两次都输出爱你,因为两次访问的都是同一个实例。,如果scope设置了"prototype"则输出的分别是爱你和null,因为两次访问的是不同的实例,所以helloworld2并没有设置Msg,
关于Spring Bean的生命周期:(init和destroy)
方式一:实现InitializingBean和DisposableBean接口,重写对应的方法,这时配置文件中不需要修改
public class Helloworld implements InitializingBean,DisposableBean{
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实例化");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁");
}
}
方式二:不需要实现接口,直接在类里写初始化和销毁的方法
public void init() {
System.out.println("实例化");
}
public void destroy() {
System.out.println("销毁");
}
但是要在配置文件中配置
<bean id="helloWorld" class="com.yzx.spring.test.Helloworld" init-method="init" destroy-method="destroy">
</bean>
方法三:如果有太多的相同名称的初始化和销毁方法的Bean,可以在配置文件中设置默认的初始化和销毁方法,(在beans标签中添加default-init-method和default-destroy-method)
<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"
default-init-method="init"
default-destroy-method="destroy">
需要注册在一个AbstractApplicationContext类中声明的关闭 hook 的 registerShutdownHook() 方法。它将确保正常关闭,并且调用相关的 destroy 方法。
@Test
public void initAnddestroy(){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Helloworld helloworld = (Helloworld) context.getBean("helloWorld");
helloworld.setMsg("爱你");
System.out.println(helloworld.getMsg());
context.registerShutdownHook();
}
另外需要注意的是,如果在bean中设置了scrop="prototype",则无法调用destroy方法,原因我百度了一下:
“对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个 prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责.”
Spring Bean后置处理器
我的理解就是定义一个类(比如InitHelloWorld.java)实现接口BeanPostProcessor ,
实现两个方法:postProcessAfterInitialization和postProcessBeforeInitialization
然后注册bean,
<bean class="com.yzx.spring.test.InitHelloWorld" />
ApplicationContext 会自动检测由 BeanPostProcessor 接口的实现定义的 bean,注册这些 bean 为后置处理器,然后通过在容器中创建 bean,在适当的时候调用它。
这样在bean实例化之前和实例化之后会执行相应的逻辑
另外发现只要执行了
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
postProcessAfterInitialization和postProcessBeforeInitialization方法就会执行,但只执行了一次
Spring Bean的继承:
helloIndia继承了helloWorld,重写了message1,继承了message2,扩展了message3
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
</bean>
<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
<property name="message1" value="Hello India!"/>
<property name="message3" value="Namaste India!"/>
</bean>
Bean 定义模板
<bean id="beanTeamplate" abstract="true">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
<property name="message3" value="Namaste India!"/>
</bean>
<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
<property name="message1" value="Hello India!"/>
<property name="message3" value="Namaste India!"/>
</bean>