Spring3学习笔记之(spring core之DI配置使用2)
来源:互联网 发布:吉首大学网络缴费 编辑:程序博客网 时间:2024/06/03 17:04
上一章节已经介绍了注入常量、集合等基本数据类型和集合数据类型,本小节将介绍注入依赖Bean及注入内部Bean。引用其他Bean的步骤与注入常量的步骤一样,可以通过构造器注入及setter注入引用其他Bean,只是引用其他Bean的注入配置稍微变化了一下:可以将“<constructor-arg index="0" value="Hello World!"/>”和“<property name="message" value="Hello World!"/>”中的value属性替换成bean属性,其中bean属性指定配置文件中的其他Bean的id或别名。另一种是把<value>标签替换为<.ref bean=”beanName”>,bean属性也是指定配置文件中的其他Bean的id或别名。那让我们看一下具体配置吧:
一、构造器注入方式:
(1)通过” <constructor-arg>”标签的ref属性来引用其他Bean,这是最简化的配置:
(2)通过” <constructor-arg>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean:
二、setter注入方式:
(1)通过” <property>”标签的ref属性来引用其他Bean,这是最简化的配置:
(2)通过” <property>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean:
三、接下来让我们用个具体例子来讲解一下具体使用吧:
(1)首先让我们定义测试引用Bean的类,在此我们可以使用原有的HelloApi实现,然后再定义一个装饰器来引用其他Bean,具体装饰类如下:
package cn.javass.spring.chapter3.bean;import cn.javass.spring.chapter2.helloworld.HelloApi;public class HelloApiDecorator implements HelloApi {private HelloApi helloApi;//空参构造器 public HelloApiDecorator() {}//有参构造器 public HelloApiDecorator(HelloApi helloApi) { this.helloApi = helloApi;} public void setHelloApi(HelloApi helloApi) { this.helloApi = helloApi; } @Override public void sayHello() { System.out.println("==========装饰一下==========="); helloApi.sayHello(); System.out.println("==========装饰一下==========="); }}(2)定义好了测试引用Bean接下来该在配置文件(resources/chapter3/beanInject.xml)进行配置Bean定义了,在此将演示通过构造器及setter方法方式注入依赖Bean:
<!-- 定义依赖Bean --><bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/><!-- 通过构造器注入 --><bean id="bean1" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"><constructor-arg index="0" ref="helloApi"/></bean><!-- 通过构造器注入 --><bean id="bean2" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"> <property name="helloApi"><ref bean=" helloApi"/></property></bean>(3)测试一下吧,测试代码(cn.javass.spring.chapter3.DependencyInjectTest)片段如下:
@Testpublic void testBeanInject() { BeanFactory beanFactory =new ClassPathXmlApplicationContext("chapter3/beanInject.xml"); //通过构造器方式注入 HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class); bean1.sayHello(); //通过setter方式注入 HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class); bean2.sayHello();}
四、其他引用方式:除了最基本配置方式以外,Spring还提供了另外两种更高级的配置方式,<ref local=””/>和<ref parent=””/>:
(1)<ref local=””/>配置方式:用于引用通过<bean id=”beanName”>方式中通过id属性指定的Bean,它能利用XML解析器的验证功能在读取配置文件时来验证引用的Bean是否存在。因此如果在当前配置文件中有相互引用的Bean可以采用<ref local>方式从而如果配置错误能在开发调试时就发现错误。
如果引用一个在当前配置文件中不存在的Bean将抛出如下异常:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line21 inXML document from class path resource [chapter3/beanInject2.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-id.1: There is no ID/IDREF binding for IDREF 'helloApi'.
<ref local>具体配置方式如下:
(2)<ref parent=””/>配置方式:用于引用父容器中的Bean,不会引用当前容器中的Bean,当然父容器中的Bean和当前容器的Bean是可以重名的,获取顺序是先查找当前容器中的Bean,如果找不到再从父容器找。具体配置方式如下:
接下来让我们用个例子演示一下<ref local>和<ref parent>的配置过程:
首先还是准备测试类,在此我们就使用以前写好的HelloApiDecorator和HelloImpl4类;其次进行Bean定义,其中当前容器bean1引用本地的”helloApi”,而”bean2”将引用父容器的”helloApi”,配置如下:
<!-- sources/chapter3/parentBeanInject.xml表示父容器配置--><!--注意此处可能子容器也定义一个该Bean--><bean id="helloApi" class="cn.javass.spring.chapter3.HelloImpl4"><property name="index" value="1"/><property name="message" value="Hello Parent!"/></bean>
<!-- sources/chapter3/localBeanInject.xml表示当前容器配置--><!-- 注意父容器中也定义了id 为 helloApi的Bean --><bean id="helloApi" class="cn.javass.spring.chapter3.HelloImpl4"><property name="index" value="1"/> <property name="message" value="Hello Local!"/></bean><!-- 通过local注入 --><bean id="bean1" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"><constructor-arg index="0"><ref local="helloApi"/></constructor-arg></bean><!-- 通过parent注入 --><bean id="bean2" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"><property name="helloApi"><ref parent="helloApi"/></property></bean>
@Testpublic void testLocalAndparentBeanInject() {//初始化父容器ApplicationContext parentBeanContext =new ClassPathXmlApplicationContext("chapter3/parentBeanInject.xml");//初始化当前容器ApplicationContext beanContext = new ClassPathXmlApplicationContext(new String[] {"chapter3/localBeanInject.xml"}, parentBeanContext); HelloApi bean1 = beanContext.getBean("bean1", HelloApi.class); bean1.sayHello();//该Bean引用local beanHelloApi bean2 = beanContext.getBean("bean2", HelloApi.class);bean2.sayHello();//该Bean引用parent bean}
“bean1”将输出“Hello Local!”表示引用当前容器的Bean,”bean2”将输出“Hello Paren!”,表示引用父容器的Bean,如配置有问题请参考cn.javass.spring.chapter3.DependencyInjectTest中的testLocalAndparentBeanInject测试方法。
内部Bean定义
内部Bean就是在<property>或<constructor-arg>内通过<bean>标签定义的Bean,该Bean不管是否指定id或name,该Bean都会有唯一的匿名标识符,而且不能指定别名,该内部Bean对其他外部Bean不可见,具体配置如下:
(1)让我们写个例子测试一下吧,具体配置文件如下:
<bean id="bean" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"><property name="helloApi"><bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/></property></bean>
@Testpublic void testInnerBeanInject() {ApplicationContext context =new ClassPathXmlApplicationContext("chapter3/innerBeanInject.xml");HelloApi bean = context.getBean("bean", HelloApi.class);bean.sayHello();}
处理null值
Spring通过<value>标签或value属性注入常量值,所有注入的数据都是字符串,那如何注入null值呢?通过“null”值吗?当然不是因为如果注入“null”则认为是字符串。Spring通过<null/>标签注入null值。即可以采用如下配置方式:
对象图导航注入支持
所谓对象图导航是指类似a.b.c这种点缀访问形式的访问或修改值。Spring支持对象图导航方式依赖注入。对象图导航依赖注入有一个限制就是比如a.b.c对象导航图注入中a和b必须为非null值才能注入c,否则将抛出空指针异常。
Spring不仅支持对象的导航,还支持数组、列表、字典、Properties数据类型的导航,对Set数据类型无法支持,因为无法导航。
数组和列表数据类型可以用array[0]、list[1]导航,注意”[]”里的必须是数字,因为是按照索引进行导航,对于数组类型注意不要数组越界错误。
字典Map数据类型可以使用map[1]、map[str]进行导航,其中“[]”里的是基本类型,无法放置引用类型。
让我们来练习一下吧。首先准备测试类,在此我们需要三个测试类,以便实现对象图导航功能演示:
NavigationC类用于打印测试代码,从而观察配置是否正确;具体类如下所示:
package cn.javass.spring.chapter3.bean;public class NavigationC { public void sayNavigation() { System.out.println("===navigation c"); }}NavigationB类,包含对象和列表、Properties、数组字典数据类型导航,而且这些复合数据类型保存的条目都是对象,正好练习一下如何往复合数据类型中注入对象依赖。具体类如下所示:
package cn.javass.spring.chapter3.bean;import java.util.List;import java.util.Map;import java.util.Properties;public class NavigationB { private NavigationC navigationC; private List<NavigationC> list; private Properties properties; private NavigationC[] array = new NavigationC[1]; private Map<String, NavigationC> map; //由于setter和getter方法占用太多空间,故省略,大家自己实现吧}NavigationA类是我们的前端类,通过对它的导航进行注入值,具体代码如下:
package cn.javass.spring.chapter3.bean;public class NavigationA { private NavigationB navigationB; public void setNavigationB(NavigationB navigationB) { this.navigationB = navigationB; } public NavigationB getNavigationB() { return navigationB; }}
接下来该进行Bean定义配置(resources/chapter3/navigationBeanInject.xml)了,首先让我们配置一下需要被导航的数据,NavigationC和NavigationB类,其中配置NavigationB时注意要确保比如array字段不为空值,这就需要或者在代码中赋值如“NavigationC[] array = new NavigationC[1];”,或者通过配置文件注入如“<list></list>”注入一个不包含条目的列表。具体配置如下:
<bean id="c" class="cn.javass.spring.chapter3.bean.NavigationC"/><bean id="b" class="cn.javass.spring.chapter3.bean.NavigationB"><property name="list"><list></list></property> <property name="map"><map></map></property> <property name="properties"><props></props></property></bean>
配置完需要被导航的Bean定义了,该来配置NavigationA导航Bean了,在此需要注意,由于“navigationB”属性为空值,在此需要首先注入“navigationB”值;还有对于数组导航不能越界否则报错;具体配置如下:
<bean id="a" class="cn.javass.spring.chapter3.bean.NavigationA"><!-- 首先注入navigatiionB 确保它非空 --><property name="navigationB" ref="b"/><!-- 对象图导航注入 --><property name="navigationB.navigationC" ref="c"/><!-- 注入列表数据类型数据 --><property name="navigationB.list[0]" ref="c"/><!-- 注入map类型数据 --><property name="navigationB.map[key]" ref="c"/><!-- 注入properties类型数据 --><property name="navigationB.properties[0]" ref="c"/><!-- 注入properties类型数据 --><property name="navigationB.properties[1]" ref="c"/><!-- 注入数组类型数据 ,注意不要越界--><property name="navigationB.array[0]" ref="c"/></bean>
配置完毕,具体测试代码在cn.javass.spring.chapter3. DependencyInjectTest,让我们看下测试代码吧:
@Testpublic void testNavigationBeanInject() {ApplicationContext context =new ClassPathXmlApplicationContext("chapter3/navigationBeanInject.xml"); NavigationA navigationA = context.getBean("a", NavigationA.class);navigationA.getNavigationB().getNavigationC().sayNavigation();navigationA.getNavigationB().getList().get(0).sayNavigation();navigationA.getNavigationB().getMap().get("key").sayNavigation();navigationA.getNavigationB().getArray()[0].sayNavigation();((NavigationC)navigationA.getNavigationB().getProperties().get("1")).sayNavigation(); }
配置简写
让我们来总结一下依赖注入配置及简写形式,其实我们已经在以上部分穿插着进行简化配置了:
一、构造器注入:
1)常量值
简写:<constructor-arg index="0" value="常量"/>
全写:<constructor-arg index="0"><value>常量</value></constructor-arg>
2)引用
简写:<constructor-arg index="0" ref="引用"/>
全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>
二、setter注入:
1)常量值
简写:<property name="message" value="常量"/>
全写:<property name="message"><value>常量</value></ property>
2)引用
简写:<property name="message" ref="引用"/>
全写:<property name="message"><ref bean="引用"/></ property>
3)数组:<array>没有简写形式
4)列表:<list>没有简写形式
5)集合:<set>没有简写形式
6)字典
简写:<map>
<entry key="键常量" value="值常量"/>
<entry key-ref="键引用" value-ref="值引用"/>
</map>
全写:<map>
<entry><key><value>键常量</value></key><value>值常量</value></entry>
<entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
</map>
7)Properties:没有简写形式
三、使用p命名空间简化setter注入:
使用p命名空间来简化setter注入,具体使用如下:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="bean1" class="java.lang.String"> <constructor-arg index="0" value="test"/> </bean><bean id="idrefBean1" class="cn.javass.spring.chapter3.bean.IdRefTestBean"p:id="value"/><bean id="idrefBean2" class="cn.javass.spring.chapter3.bean.IdRefTestBean"p:id-ref="bean1"/></beans>
- xmlns:p="http://www.springframework.org/schema/p" :首先指定p命名空间;
- <bean id="……" class="……" p:id="value"/> :常量setter注入方式,其等价于<property name="id" value="value"/>;
- <bean id="……" class="……" p:id-ref="bean1"/> :引用setter注入方式,其等价于<property name="id" ref="bean1"/>。
- Spring3学习笔记之(spring core之DI配置使用2)
- Spring3学习笔记之(spring core之DI配置使用1)
- Spring3 学习笔记之(spring core 之IoC配置使用)
- Spring3学习笔记之(spring core 之DI(Bean作用域))
- Spring3学习笔记之(spring core之DI循环依赖)
- Spring3学习笔记之(Spring core 之DI 更多知识点(延迟加载和自动装配))
- spring3学习笔记之(spring core 之DI 更多知识点(依赖检查和方法注入))
- Spring3 学习笔记之(spring core 之IoC基础)
- Spring3学习笔记之(spring core之IoC容器基本原理)
- Spring之DI的配置使用
- Spring学习笔记(一)----IoC之DI
- Spring学习笔记之基础、IOC、DI(1)
- Spring学习笔记(一)----IoC之DI
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
- 关于二分查找 二叉树 二叉排序树 平衡二叉树 b树 b+树 mysql索引 字典树的开放思考(整理后)
- String.getBytes()和对象序列化
- 在多个点中找斜率最大的两个点确定的直线 nlg(n)
- iOS开发-xcode使用-自动格式化代码
- 面试经验+学习建议+未来规划
- Spring3学习笔记之(spring core之DI配置使用2)
- android调用系统相机拍照并保存在本地
- 在实验室,心态很关键
- 杂(各类小细节)
- java中获得RGB值 并显示
- XMPP
- Xmpp分组
- Android基于XMPP Smack Openfire下学习开发IM(一)实现用户注册、登录、修改密码和注销等
- Xmpp工具