Bean的装配
Bean的装配,就是Bean对象的创建,容器根据代码要求创建Bean对象后再传递给代码的过程,称为Bean的装配
Bean的默装配方式
通过getBean()方式从容器中获取指定的Bean实例,容器首先会调用Bean类的无参数构造器,创建空值的实例对象。
示例:
AService.java
package com.bean01;
public interface AService {
void doSome();
}
AServiceImpl.java
package com.bean01;
public class ASereviceImpl implements AService {
//spring默认的是调用类的无参数构造方法,创建空值对象
public ASereviceImpl() {
super();
System.out.println("ASereviceImpl的无参构造方法");
}
@Override
public void doSome() {
System.out.println("==--业务方法doSome()--==");
}
}
applicationContext.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.xsd">
<!-- 声明bean对象
id:对象名称,唯一值。
class:全限定的类名 不能是接口
-->
<!-- bean标签的作用等同于
SomeService someService = new SomeServiceImpl() -->
<bean id="aService" class="com.bean01.ASereviceImpl" />
</beans>
MyTest.java
package com.bean01;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class MyTest {
/**
* spring容器中的对象是什么时间创建的?
* 在创建容器对象的时候,会创建配置文件中的所有对象
* 优点:一次创建所有对象,在使用getBean()获取对象时速度快
* 缺点:占用内存
*/
@Test
public void test01() {
String configLocation = "com/bean01/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
//对象相当于已经存放在了spring的map中 (getBean()源码)
AService service = (AService) ctx.getBean("aService");
service.doSome();
}
}
容器中Bean的作用域
创建Bean示例的时候,可以通过scope属性,为Bean()指定特定的作用域。
Spring支持5种作用域(主要会用到的有以下4种):
(1)singleton: 单例模式。在Spring容器中,使用singleton定义的Bean将是一个单例的,只有一个实例。默认的作用域就是单例的。
(2)prototype:原型模式。每次使用getBean()方法获取的同一个< bean />的实例都是一个新的实例。
(3)request:对于每次HTTP请求,都将会产生一个不同的Bean实例。
(4)session:对于每个不同的HTTP session,都将产生一个不同的Bean实例。
注意:
对于scope为singleton的单例模式,Bean是在容器被创建时即被装配好了。
对于scope为prototype的原型模式,Bean实例是在代码中使用到该Bean实例时才进行装配的。
示例(单例模式):
applicationContext.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.xsd">
<!--
定义对象的作用域,指定对象的存在范围和可见性
1.singleton 单例,这是默认值,表示在spring容器中对象只有一个
如何指定单例:
<bean id="xx" class="yyy" scope="singleton" />
2.prototype 原型,表示每次使用getBean()都会创建一个新的对象
如何指定原型作用域:
<bean id="xx" class="yyy" scope="prototype" />
-->
<!-- 单例 -->
<bean id="aService" class="com.bean02.ASereviceImpl" scope="singleton" />
</beans>
MyTest.java
package com.bean02;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class MyTest {
/**
* 单例对象是什么时间创建的?
* 创建容器对象的时候,会创建配置文件中的所有对象
*/
@Test
public void test01() {
String configLocation = "com/bean02/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
//单例对象
AService service1 = (AService) ctx.getBean("aService");
AService service2 = (AService) ctx.getBean("aService");
//判断对象是否为同一个
if (service1 == service2) {
System.out.println("service1和service2是同一个对象");
} else {
System.out.println("service1和service2【不是】同一个对象");
}
}
}
示例(原型模式):
applicationContext.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.xsd">
<!--
定义对象的作用域,指定对象的存在范围和可见性
1.singleton 单例,这是默认值,表示在spring容器中对象只有一个
如何指定单例:
<bean id="xx" class="yyy" scope="singleton" />
2.prototype 原型,表示每次使用getBean()都会创建一个新的对象
如何指定原型作用域:
<bean id="xx" class="yyy" scope="prototype" />
-->
<!-- 原型 -->
<bean id="aService" class="com.bean02.ASereviceImpl" scope="prototype" />
</beans>
MyTest.java
package com.bean02;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class MyTest {
/**
* 测试原型作用域
* 原型作用域的对象创建时间?
* 把对象的创建时间延迟到使用对象的时候(调用getBean()之后才创建)
*/
@Test
public void test02() {
String configLocation = "com/bean02/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
//原型作用域对象 调用getBean()创建出来到本方法结束,该对象就不存在了 相当于是没有存放在getBean()的map中的
AService service1 = (AService) ctx.getBean("aService");
AService service2 = (AService) ctx.getBean("aService");
System.out.println("service1: " + service1.hashCode());
System.out.println("service2: " + service2.hashCode());
if (service1 == service2) {
System.out.println("service1和service2是同一个对象");
} else {
System.out.println("service1和service2【不是】同一个对象");
}
}
}
自定义Bean的生命始末
可以为Bean定制初始化后的生命行为,也可以为Bean定制销毁前的生命行为。
需要在配置文件的< bean/>标签中增加如下属性:
init-method:指定初始化方法的方法名
destroy-method:指定销毁方法的方法名
注:destroy-method实现需要两个条件:
(1)Bean为singleton
(2)确保容器关闭。关闭时,接口ApplicationContext没有close方法,但是它的实现类有,所以要将ApplicationContext对象进行强转成其实现类的对象执行close方法
示例:
AServiceImpl.java
package com.bean03;
public class ASereviceImpl implements AService {
//spring默认的是调用类的无参数构造方法,创建空值对象
public ASereviceImpl() {
super();
System.out.println("ASereviceImpl的无参构造方法");
}
@Override
public void doSome() {
System.out.println("==--业务方法doSome()--==");
}
//定义bean的生命始末方法
/**
* 初始化方法,作用是创建其他对象,给属性赋值,等同于构造方法的作用
*/
public void setUp() {
System.out.println("bean的初始化方法,等同于构造方法的作用");
}
/**
* bean销毁之前执行的方法,只要是用来回收资源,释放内存
*/
public void tearDown() {
System.out.println("bean销毁之前执行的方法,用来回收资源");
}
}
applicationContext.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.xsd">
<!--
bean的生命始末 可以参与到spring创建对象,和销毁对象的过程中,自定义一些操作
1.在代码中定义生命始末的方法,方法的原型是 public void 方法名自定义() {自定义的操作}
2.在spring的配置文件中,定义bean对象的时候,指定方法名称
<bean id="xx" class="yyy" init-method="bean的初始化方法名称"
destroy-method="bean对象销毁之前执行的方法名称" />
两个方法不需要同时存在
-->
<bean id="aService" class="com.bean03.ASereviceImpl" init-method="setUp"
destroy-method="tearDown" />
</beans>
MyTest.java
package com.bean03;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class MyTest {
@Test
public void test01() {
String configLocation = "com/bean03/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
//单例对象
AService service = (AService) ctx.getBean("aService");
service.doSome();
/**
* AService service = new AServiceImpl();
* service.setUp();
*/
/**
* 执行销毁方法
* 1.关闭容器
* 2.对象得是单例的
* 因为是单例的对象存放在容器之中 原型的没有存放在容器中,所以会无法执行销毁方法
*/
((ClassPathXmlApplicationContext)ctx).close(); //Map
}
}
结束语
我喜欢吃肉,我不是英雄,我只做我想做的事,保护我想要保护的人而已。 ——路飞《海贼王》