众所周知,spring的bean在spring上下文的范围内默认是单例的,但通过将bean标签的scope属性显式的标记为prototype,可以使其变为非单例的。
下面就写几行程序来验证一下这个结论,程序用到一个调用者
接口Referer和被调用者接口Referee:
class="java" name="code">package refer;
public interface Referer
{
void order();
}
package refer;
public interface Referee
{
void speak();
}
ChenReferer实现了调用者接口,guangReferee实现了被调用者接口:
package refer;
public class ChenReferer implements Referer
{
public Referee guang;
public Referee getGuang()
{
return guang;
}
public void setGuang(Referee guang)
{
this.guang = guang;
}
public void order()
{
System.out.println("I am chen and my address is: " + this.toString().split("@")[1]);
guang.speak();
}
}
package refer;
public class guangReferee implements Referee
{
public void speak() {
System.out.println("I am guang and my address is: " + this.toString().split("@")[1]);
}
}
将调用者和被调用者的实现类的装配信息放入同一个包下的beans.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="chen" class="refer.ChenReferer">
<property name="guang" ref="guang" />
</bean>
<bean id="guang" class="refer.guangReferee">
</bean>
</beans>
注意bean chen此时没有设置属性scope="prototype"
下面是主方法:
package refer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDemo
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("refer/beans.xml");
Referer chen = (Referer) context.getBean("chen");
Referer chen1 = (Referer) context.getBean("chen");
chen.order();
chen1.order();
}
}
主方法加载了spring配置文件,第11行和第12行分别两次从spring容器中取出id为chen的bean,运行之,控制台显示:
I am chen and my address is: 259c259c
I am guang and my address is: 608a608a
I am chen and my address is: 259c259c
I am guang and my address is: 608a608a
我们可以看到两个chen的物理地址是相同的,虽然两次从容器中取bean,但是得到的只是同一个ChenReferer对象,证明其在上下文范围内的单例性。
下面再将beans.xml中bean chen加一个属性值scope的声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="chen" class="refer.ChenReferer" scope="prototype">
<property name="guang" ref="guang" />
</bean>
<bean id="ling" class="refer.LingReferer">
<property name="guang" ref="guang" />
</bean>
<bean id="guang" class="refer.guangReferee">
</bean>
</beans>
再运行主方法,结果为:
I am chen and my address is: 18561856
I am guang and my address is: 58cc58cc
I am chen and my address is: dc00dc0
I am guang and my address is: 58cc58cc
两次的chen物理地址是不同的,证明在
第二次getBean方法调用时bean容器重新生成了一个ChenReferer对象。
同样的情况适用于被引用的对象,我们新加一个调用者LingReferer:
package refer;
public class LingReferer implements Referer
{
public Referee guang;
public Referee getGuang()
{
return guang;
}
public void setGuang(Referee guang)
{
this.guang = guang;
}
public void order()
{
System.out.println("I am ling and my address is: " + this.toString().split("@")[1]);
guang.speak();
}
}
beans.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="chen" class="refer.ChenReferer" scope="prototype">
<property name="guang" ref="guang" />
</bean>
<bean id="ling" class="refer.LingReferer">
<property name="guang" ref="guang" />
</bean>
<bean id="guang" class="refer.guangReferee">
</bean>
</beans>
此时bean guang的scope不是prototype的。
修改后的主方法:
package refer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDemo
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("refer/beans.xml");
Referer chen = (Referer) context.getBean("chen");
Referer ling = (Referer) context.getBean("ling");
chen.order();
ling.order();
}
}
运行之,结果为:
I am chen and my address is: 371a371a
I am guang and my address is: 67146714
I am ling and my address is: 259c259c
I am guang and my address is: 67146714
虽然两个不同的调用者chen和ling分别都引用了guang,但是由于bean guang不是上下文单例的,所以它们引用的是同一个guangReferee对象。
再次更改beans.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="chen" class="refer.ChenReferer" scope="prototype">
<property name="guang" ref="guang" />
</bean>
<bean id="ling" class="refer.LingReferer">
<property name="guang" ref="guang" />
</bean>
<bean id="guang" class="refer.guangReferee" scope="prototype">
</bean>
</beans>
主方法不变,运行,得:
I am chen and my address is: b440b44
I am guang and my address is: d520d52
I am ling and my address is: 5ca45ca4
I am guang and my address is: 3aac3aac
由于bean guang被设置为上下文非单例的,所以在运行期,spring容器分别生成了两个不同的guangReferee对象,chen和ling分别引用了它们。