这一次的学习主要是对配置的一些特殊属性进行了解和使用。
首先我们要了解的第一个属性就是idref,在前面的学习中我们已经接触到ref这个属性,那么idref和ref这两个属性有什么区别呢,事实上它们两个虽然长得很相似但是却不怎么相干,ref这个属性我们通过前面的学习已经知道,它的作用就是用来引用一个bean的实例用来实现依赖注入的功能,而idref则是用来引用bean的名字的注意是名字而不是实例,一个字符串而已。按照官方文档的说法就是idref是用来将容器中其他bean的id传给<constructor-arg/> 或 <property/> 元素。然后Spring容器可以在工程部署的时校验引用的名字是否存在,其实就是检查bean是不是真的有,降低工程上线运行时的风险。这里面还有一个属性local,配合idref使用更加有效,它可以将校验提前到书写配置的时候,而不必等到工程部署时。其实在我们一般的开发过程中很少用这个属性,但对一些要求比较高的项目而言这个功能还是有一定意义的,毕竟软件开发中问题的及早暴露,能最有效避免掉出现更大麻烦的可能。
我们这里还是先通过一个小程序,来演示一些这个属性的作用。
定义一个TargetBean类,可以没有属性
然后定义一个ClientBean类,如下:
public class ClientBean {
private String tbean;
public String getTbean() {
return tbean;
}
public void setTbean(String tbean) {
this.tbean = tbean;
}
}
配置文件bean.xml
<bean id="TargetBean" class="cn.com.spring.injection.bean.TargetBean"/>
<bean id="ClientBean" class="cn.com.spring.injection.bean.ClientBean">
<property name="tbean"><idref bean="TargetBean"/></property>
</bean>
使用Junit测试程序如下:
public class TestUtils extends TestCase {
private ApplicationContext actx = new FileSystemXmlApplicationContext("bean.xml");
@Test
public void test(){
ClientBean exampleBean = (ClientBean)actx.getBean("ClientBean");
System.out.println(exampleBean.getTbean());
}
}
运行结果
TargetBean
修改配置文件bean.xml
将TargetBean的配置去掉
然后再次运行,结果失败
再次修改配置文件bean.xml如下
<idref local="TargetBean"/>
发现配置文件报错
这里由于是java工程,就没有部署的步骤,但是通过最后一次的修改可以发现,Spring已经检查到idref引用的bean名字不存在并报错了。
下面我们来学习一下ref这个标签,ref有三个属性,bean,local,parent
我们前面的章节的学习已经接触到ref这个标签了,同时使用了其bean属性,其实很简单bean属性就是要引用的Bean的id名称,下面来说介绍一下它另外两个属性local,parent。
bean的使用范围比较广,使用条件比较弱,几乎在任何情况下都可以使用,属于通吃型的。
local的使用就受点限制,它所引用的bean必须是在当前文件中定义的否则会报错,所以在配置不复杂的情况下最好是用这个,因为它能帮
助你提前校验配置书写是否正确。bean属性则不受这个限制所以Spring容器也就无法事先去校验你书写的配置是否正确。
parent的使用条件比较强,它只能指定位于当前容器的父容器中定义的对象引用,所以这个属性使用就比较少。这里提到了一个父容器的慨念在下面的示例程序中将会有所体现。
下面我改造一下上面的小程序
TargetBean.java
public class TargetBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ClientBean.java
public class ClientBean {
private TargetBean tbean;
public TargetBean getTbean() {
return tbean;
}
public void setTbean(TargetBean tbean) {
this.tbean = tbean;
}
}
配置文件
<bean id="TargetBean" class="cn.com.spring.injection.bean.TargetBean">
<property name="name" value="targetBean"/>
</bean>
<bean id="ClientBean" class="cn.com.spring.injection.bean.ClientBean">
<property name="tbean"><ref bean="TargetBean"/></property>
</bean>
测试程序:
public void test1(){
ClientBean exampleBean = (ClientBean)actx.getBean("ClientBean");
System.out.println(exampleBean.getTbean().getName());
}
运行结果:
targetBean
下面我们修改配置文件,将ref的bean属性修改为local后,再次运行测试程序和上次一样,说明在目前这种配置情况下
这两个属性是几乎没什么区别
下面我们将配置文件分成两个bean1.xml和bean.xml
bean1.xml配置TargetBean
<bean id="TargetBean" class="cn.com.spring.injection.bean.TargetBean">
<property name="name" value="targetBean"/>
</bean>
bean.xml配置ClientBean
<import resource="bean1.xml"/>
<bean id="ClientBean" class="cn.com.spring.injection.bean.ClientBean">
<property name="tbean"><ref bean="TargetBean"/></property>
</bean>
执行测试程序发现结果仍然没有问题,但是此时如果将ref的bean改为local,xml文件就会报错,这也验证了local属性的使用条件,所以在同一个配置文件里使用local确实是比bean更好的选择,但是一般在项目开发中配置文件通常是复杂的并且也不只是一个,因此如果对Spring玩的不是很转还是使用bean吧。
下面再来演示一下parent属性,这个玩起来有点麻烦,我们依然是对上面的示例程序进行改造
TargetBean.java不变
ClientBean.java如下
public class ClientBean {
private TargetBean tb;
private String flag;
public TargetBean getTb() {
return tb;
}
public void setTb(TargetBean tb) {
this.tb = tb;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
}
配置文件还是要使用两个我们这里选bean1.xml为父容器,bean.xml为子容器
bean1.xml
<bean id="TargetBean" class="cn.com.spring.injection.bean.TargetBean">
<property name="name" value="targetBeanChild"/>
</bean>
<bean id="TargetBeanParent" class="cn.com.spring.injection.bean.TargetBean">
<property name="name" value="targetBeanParent"/>
</bean>
bean.xml
<bean id="TargetBean" class="cn.com.spring.injection.bean.ClientBean">
<property name="tb"><ref parent="TargetBean"/></property>
<property name="flag" value="clientBean"/>
</bean>
测试程序如下:
public class TestUtils extends TestCase {
private ApplicationContext parent = new FileSystemXmlApplicationContext("bean1.xml");
private ApplicationContext child = new FileSystemXmlApplicationContext(new String[]{"bean.xml"},parent);
@Test
public void test1(){
TargetBean tbean = (TargetBean)parent.getBean("TargetBean");
TargetBean tbean1 = (TargetBean)child.getBean("TargetBeanParent");
ClientBean exampleBean = (ClientBean)child.getBean("TargetBean");
System.out.println(tbean.getName());
System.out.println(tbean1.getName());
System.out.println(exampleBean.getTb().getName());
System.out.println(exampleBean.getFlag());
System.out.println(tbean.getName());
}
}
这里注意一下父容器和子容器的设定是通过程序进行的。
运行一下结果如下:
targetBeanChild
targetBeanParent
targetBeanChild
clientBean
targetBeanChild
这里面要注意的就只有两点,一是父容器和子容器是由程序设定的,二是两个配置文件的联系如果使用parent标签bean属性id要和父容器的相同