- 本文是接着这篇文章写的。Spring-IOC创建对象的三种方式
- 参考: Spring详解(二)------IOC控制反转
Spring容器创建对象的时机
1、默认的情况下,启动spring容器时,编创建对象,(遇到bean便创建对象)
测试:
在HelloIoc.java中添加构造方法
/**
* @author wangxl
* @ClassName HelloIoc
* @Description TODO
* @date 2019/10/14 17:29
*/
public class HelloIoc {
//默认构造函数
public HelloIoc() {
System.out.println("Hello default Constructor");
}
/**
* sayHello方法
*/
public void sayHello() {
System.out.println("Hello IOC");
}
}
- 在 applicationContext.xml 文件中添加 bean(由于上面我们通过三种方式来创建对象了,里面已经有三个bean了)
- 启动 Spring 容器,查看无参构造函数的打印次数
测试:
/**
* 只启动Spring容器
*/
@Test
public void whenCreateObject(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
}
结果:
十月 17, 2019 2:00:08 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5ccd43c2: startup date [Thu Oct 17 14:00:08 CST 2019]; root of context hierarchy
十月 17, 2019 2:00:09 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Hello default Constructor
Hello default Constructor
实例工厂方法构造函数
Hello default Constructor
2、在spring的配置文件bean中有一个属性 lazy-init="default/true/false"
①、如果lazy-init为"default/false"在启动spring容器时创建对象(默认情况)
②、如果lazy-init为"true",在context.getBean时才要创建对象
image.png
测试结果:
如果lazy-init为"default/false"在启动spring容器时创建对象(默认情况),没有getBean()
十月 17, 2019 2:02:45 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5ccd43c2: startup date [Thu Oct 17 14:02:45 CST 2019]; root of context hierarchy
十月 17, 2019 2:02:46 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Hello default Constructor
实例工厂方法构造函数
Hello default Constructor
当lazy-init = "true" 时,我们执行getbean()方法,Spring容器才会去创建对象。
@Test
public void iocTest() {
//1.启动spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从spring容器中取出数据
HelloIoc ioc = (HelloIoc) applicationContext.getBean("helloIoc");
}
测试结果:
十月 17, 2019 2:05:22 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5ccd43c2: startup date [Thu Oct 17 14:05:22 CST 2019]; root of context hierarchy
十月 17, 2019 2:05:23 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Hello default Constructor
实例工厂方法构造函数
Hello default Constructor
Hello default Constructor
小结:
第一种情况下:
在启动Spring容器的时候,会检查 Spring容器的配置文件的正确性,如果再结合tomcat,当spring容器不能正常启动时,整个tomcat就不能正常启动。但是这样的缺点就是把一些bean过早的放在了内存中,如果有数据的话,则对内存就是一个消耗。
在第二种情况下:
可以较少内存消耗,但是不容易发生错误。
Spring的Bean中的 scope属性
- 1、默认的scope的值是singleton,即产生的对象是单例的。
applicationContext.xml 文件中配置:
<bean id="helloIoc" scope="singleton" class="com.ys.ioc.HelloIoc" ></bean>
测试验证
//spring 容器默认产生对象是单例的 scope="singleton"
@Test
public void test_scope_single_CreateObject(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc hello1 = (HelloIoc) context.getBean("helloIoc");
HelloIoc hello2 = (HelloIoc) context.getBean("helloIoc");
System.out.println(hello1.equals(hello2)); //true
}
- 2、scope=“prototype”
多例模式,并且spring容器启动的时候并不会创建对象,而是在得到 bean 的时候才会创建对象
applicationContext.xml 文件中配置:
<bean id="helloIoc" scope="prototype" class="com.ys.ioc.HelloIoc" ></bean>
测试验证
///spring 容器默认产生对象是单例的 scope="prototype"
@Test
public void test_scope_prototype_CreateObject(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloIoc hello1 = (HelloIoc) context.getBean("helloIoc");
HelloIoc hello2 = (HelloIoc) context.getBean("helloIoc");
System.out.println(hello1.equals(hello2)); //false
}
总结:
在单例的模式下,启动spring容器,便会创建对象;在多例模式下,启动容器不会创建对象,获得bean的时候才会创建对象。
Spring的Bean中的生命周期
- 创建 SpringLifeCycle.java
/**
* Spring 容器的生命周期
* @author hadoop
*
*/
public class SpringLifeCycle {
public SpringLifeCycle(){
System.out.println("SpringLifeCycle");
}
//定义初始化方法
public void init(){
System.out.println("init...");
}
//定义销毁方法
public void destroy(){
System.out.println("destroy...");
}
public void sayHello(){
System.out.println("say Hello...");
}
}
- applicationContext.xml
<bean id="springLifeCycle" init-method="init" destroy-method="destroy" class="com.ys.ioc.SpringLifeCycle"></bean>
- 测试
//spring 容器的初始化和销毁
@Test
public void testSpringLifeCycle(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SpringLifeCycle hello = (SpringLifeCycle) context.getBean("springLifeCycle");
hello.sayHello();
//销毁spring容器
ClassPathXmlApplicationContext classContext = (ClassPathXmlApplicationContext) context;
classContext.close();
}
-
控制台打印如下:
image.png - 分析:spring 容器的声明周期
1、spring容器创建对象
2、执行init方法
3、调用自己的方法
4、当spring容器关闭的时候执行destroy方法
注意:当scope为"prototype"时,调用 close() 方法时是不会调用 destroy 方法的
网友评论