前面介绍了bean的作用域,这里就引用出了一些问题,大家想想,这bean什么时候进行实例化呢?
先改为单实例模式,来看看什么时候实例化,beans.xml如下:
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-2.5.xsd">
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean">
</bean>
</beans>
<?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-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"> </bean> </beans>究竟是调用getBean方法时进行实例化?还是Spring容器起动时就进行实例化呢?下面就进行一下验证,打开PersonServiceBean.java,我们验证什么时候实例化,有个最简单的方法,在它的默认构造函数里面打印出一句话,
PersonServiceBean.java
Java代码
package cn.itcast.service.impl;
import cn.itcast.service.PersonService;
public class PersonServiceBean implements PersonService {
public PersonServiceBean(){
System.out.println("我被实例化了。。");
}
public void save(){
System.out.println("我是save()方法");
}
}
package cn.itcast.service.impl; import cn.itcast.service.PersonService; public class PersonServiceBean implements PersonService { public PersonServiceBean(){ System.out.println("我被实例化了。。"); } public void save(){ System.out.println("我是save()方法"); } }看看在默认的情况下,到底是调用getBean的时候输出这句话?还是在实例化容器的时候?
SpringTest.java
Java代码
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void instanceSpring(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
}
}
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); } }执行这个单元测试,从控制台可以看到输出了“我被实例化了”这句话,由此可见,这个实例化对于这种默认情况下(它的作用范围是单例的,而且并没有修改任何的属性),是在容器实例化的时候,就会对bean进行实例化。
如果bean的作用域范围是scope="prototype"的话,这个bean的实例化到底是在什么时候呢?是在容器实例化之后实例化?还是在调用getBean方法后实例化呢?
beans.xml
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-2.5.xsd">
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype">
</bean>
</beans>
<?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-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"> </bean> </beans>
SpringTest.java
Java代码
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.service.PersonService;
public class SpringTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void instanceSpring(){
System.out.println("11111111111");
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("22222222222222222");
PersonService personService1 = (PersonService)ctx.getBean("personService");
System.out.println("333333333333333333333");
ctx.close();
}
}
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.service.PersonService; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ System.out.println("11111111111"); ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); System.out.println("22222222222222222"); PersonService personService1 = (PersonService)ctx.getBean("personService"); System.out.println("333333333333333333333"); ctx.close(); } }输出结果是:
11111111111
22222222222222222
我被实例化了。。
333333333333333333333
这说明,当bean的作用域范围是prototpye的时候,它是在我们调用getBean方法时才进行实例化的。那么我们有没有办法去更改这种行为呢? 下面是单实例模式下,更改行为的代码
beans.xml
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-2.5.xsd">
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true">
</bean>
</beans>
<?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-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true"> </bean> </beans>lazy-init是延迟初始化属性,假如设为false,就是不进行延迟初始化,那么它就在容器实例化的时候对bean进行实例化,如果设成true的话,代表要进行延迟初始化,那么Spring容器实例化的时候不会对bean进行实例化.
运行单元测试,输出结果为:
11111111111
22222222222222222
我被实例化了。。
333333333333333333333
可以看出lazy-init这个属性是起到了作用,我们告诉它不要在Spring容器实例化的时候,对PersonServiceBean这个bean进行实例化,通过lazy-init这个属性就可以指定这种行为。
如果想为配置文件下所有的bean指定延迟初始化的话,可以在<beans>这个配置节点里面指定属性default-lazy-init="true".当然在实际运用中,是不建议大家使用这个属性的,因为我们希望在应用起动的时候我们看下控制台打印出来的信息,看一些bean是否可以完成它的实例化,如果你在调用getBean的时候才实例化这个bean,那就是说尽能在运行期才能发现错误,所以建议大家少用lazy-init这个属性,除非你要完成一些特别的工作。
现在这个bean的创建时机我们已经知道了,那么在有一些应用场合下,当它在创建bean的时候,我要执行一些资源的打开,也就是说是初始化操作(好比打开数据库连接等等的操作),这时候我们该怎么办呢?
PersonServiceBean.java如下,
Java代码
package cn.itcast.service.impl;
import cn.itcast.service.PersonService;
public class PersonServiceBean implements PersonService {
public void init(){
System.out.println("初始化");
}
public PersonServiceBean(){
System.out.println("我被实例化了。。");
}
public void save(){
System.out.println("我是save()方法");
}
public void destory(){
System.out.println("关闭打开的资源");
}
}
package cn.itcast.service.impl; import cn.itcast.service.PersonService; public class PersonServiceBean implements PersonService { public void init(){ System.out.println("初始化"); } public PersonServiceBean(){ System.out.println("我被实例化了。。"); } public void save(){ System.out.println("我是save()方法"); } public void destory(){ System.out.println("关闭打开的资源"); } }
很明显,这个init方法,如果我们不做任何指定的话,它是不会执行的,Spring容器给我们提供了一个功能,可以指定我们的初始化方法(用init-method这个属性),也就是说当PersonServiceBean这个bean被实例化之后,接下来就会执行init-method指定的方法。
当然在实际应用中,除了初始化方法对一些资源的打开,我们还需要对资源进行释放,也就是说我们要关闭一些资源,这时候呢,我们需要在PersonServiceBean这个bean被销毁之前先执行destory方法,怎么办呢?我们可以指定destory-method属性.
大家想想PersonServiceBean这个bean到底什么时候被销毁的呢?如果你没去人为的操作它的话(没有人为的把它删掉),那么默认情况下它是一直在Spring容器中的,也就是说随着Spring容器关闭了,它才会被销毁,
beans.xml
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-2.5.xsd">
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="false"
init-method="init" destory-method="destory">
</bean>
</beans>
<?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-2.5.xsd"> <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="false" init-method="init" destory-method="destory"> </bean> </beans>
SpringTest.java
Java代码
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.itcast.service.PersonService;
public class SpringTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void instanceSpring(){
System.out.println("11111111111");
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
//用到了AbstractApplicationContext这个抽象类,这个类是被ClassPathXmlApplicationContext所继承的
//所以我们可以通过AbstractApplicationContext来引用Spring容器的实例
System.out.println("22222222222222222");
PersonService personService1 = (PersonService)ctx.getBean("personService");
System.out.println("333333333333333333333");
ctx.close();//调用Spring容器里面的close方法,对容器进行正常的关闭
//以前并没有正常关闭Spring容器,因为我们的应用一执行完,这个Spring容器就被销毁了
//以前的执行方法并不是正常的关闭Spring容器,close是正常的关闭容器
}
}
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.service.PersonService; public class SpringTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ System.out.println("11111111111"); AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //用到了AbstractApplicationContext这个抽象类,这个类是被ClassPathXmlApplicationContext所继承的 //所以我们可以通过AbstractApplicationContext来引用Spring容器的实例 System.out.println("22222222222222222"); PersonService personService1 = (PersonService)ctx.getBean("personService"); System.out.println("333333333333333333333"); ctx.close();//调用Spring容器里面的close方法,对容器进行正常的关闭 //以前并没有正常关闭Spring容器,因为我们的应用一执行完,这个Spring容器就被销毁了 //以前的执行方法并不是正常的关闭Spring容器,close是正常的关闭容器 } }运行,得到输出结果:
11111111111
我被实例化了。。
初始化
22222222222222222
333333333333333333333
关闭打开的资源
首先,先执行实例化,实例化之后呢再调用init方法,大家一定要注意它的执行时机(先实例化,再执行init方法).这个方法是容器通过反射技术来调用的。
destory方法也已经被执行了
指定Bean的初始化方法和销毁方法
----------------------------------------------------------
指定Bean的初始化方法和销毁方法
<bean id="xxx" class="cn.itcast.OrderServiceBean" init-method="init" destroy-method="close"/>