Spring IOC容器之进阶篇

来源:互联网 发布:淘宝阿里医生在哪里 编辑:程序博客网 时间:2024/05/17 01:09

上一篇博客介绍了一些IOC容器的基础,这里总结一下,IOC容器的数据类型转化和代码复用的一个策略。

一、自定义数据类型转化器:

    类似Struts的数据类型的转化,诸如,java.util.Date类型的数据,如果使用Spring的容器注入,进行赋值,那么就需要自定义转换器,并集成到Spring的框架中。

    1、在Bean类中设置Date类型字段的set方法:

private Date  dateValue;public Date getDateValue() {return dateValue;}public void setDateValue(Date dateValue) {this.dateValue = dateValue;}

    2、自定义Date格式转换器的java类

    UtilDatePropertyEditor需要继承PropertyEditorSupport:

public class UtilDatePropertyEditor extends PropertyEditorSupport {//将转换格式做成可配的private String pattern;@SuppressWarnings("unused")@Overridepublic void setAsText(String text) throws IllegalArgumentException {System.out.println("--------UtilDatePropertyEditor.setAsText() ----"+text);try {//日期转化Date date = new  SimpleDateFormat(pattern).parse(text);this.setValue(date);} catch (ParseException e) {e.printStackTrace();throw new IllegalArgumentException(text);}}public void setPattern(String pattern) {this.pattern = pattern;}}

说明:

    为了让自定义转化器支持客户自定义的格式,这里使用变量的方式,交给用户在配置文件中自定义类型。另外,这个类要继承PropertyEditorSupport,需要使用this.setValue(date);将转换后的日期交给容器。


   3、将定义的转换器,配置到容器中,集成到容器中:

    将自定义的配置单独放到一个配置文件(applicationContext-editor.xml)中:

<beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     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-2.0.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">    <bean  id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">  <property name="customEditors">  <map>  <entry key="java.util.Date">  <bean class="com.bjpowernode.spring.UtilDatePropertyEditor">  <property name="pattern"  value="yyyy-MM-dd"></property>  </bean>  </entry>  </map>  </property>  </bean>  </beans>

自定义转换器的配置和普通bean的配置类似,也使用bean标签,因为其他的类不会调用自定义的转换器,所以这里就将转换器做为一种内部bean配置到了org.springframework.beans.factory.config.CustomEditorConfigurer类的内部。

也可以为自定义的转换器提供外部访问的接口:

<bean  id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">  <property name="customEditors">  <map>  <entry key="java.util.Date" value-ref="customDatePropertyConvertor">    </entry>  </map>  </property> </bean> <!-- 外部可以使用这个转换器  --> <bean id="customDatePropertyConvertor" class="com.bjpowernode.spring.UtilDatePropertyEditor">  <property name="pattern"  value="yyyy-MM-dd"></property> </bean>

不过这样做的意义不大,通常我们都会使用第一种配置方法。

    4、使用容器为Date类型字段赋值:

    上面的准备工作都做好后,就可以像普通的数据类型一样,为日期类型数据赋值注入,下面是applicationContext-beans.xml

<bean id="bean1" class="com.bjpowernode.spring.Bean1"><property name="map"><map><entry key="k1" value="v1"></entry><entry key="k2" value="v2"></entry></map></property><property name="dateValue"><value> 2013-09-28</value></property></bean>


二、代码复用策略:

    类似Hibernate的Component映射,Spring也提供了一些代码复用的机制。如果有多个Bean有公共的属性字段,那么就可以将这些字段单独抽离出,放到一个类中,让其他类来复用这块儿代码即可。

如:Bean3和Bean4都有id、name和sex属性字段,且数据类型也都一样,那么就可以这样配置:

1、将公共属性放到一个抽象bean中,为了管理的方便,这里单独放到applicationContext-common.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: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-2.0.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"><bean abstract="true" id="abstractbean" name="beancommon"><property name="id" value="111" /><property name="name" value="任我行" /><property name="sex" value="男" /></bean><bean id="bean3" class="com.bjpowernode.spring.Bean3" parent="abstractbean" /></beans>


如果Bean4又有自己特有的属性字段,那么继承了这个公共抽象bean之后,直接添加即可:

<bean id="bean4" class="com.bjpowernode.spring.Bean4" parent="abstractbean"><property name="age" value="25" /></bean>


注意:

Spring的配置文件可以有多个,也可以有一个,不管有多少个,即使在不同的配置文件中,所有的bean的id都必须是唯一的,所以,Bean4的这段代码可以放到applicationContext-common.xml文件中也可以放到applicationContext-beans.xml文件中。

如果Bean2对Bean3和Bean4都有引用,那么可以像使用其他Bean一样进行配置:

<bean id="bean2" class="com.bjpowernode.spring.Bean2"><property name="bean3" ref="bean3" /><property name="bean4" ref="bean4" /><property name="bean5" ref="bean5" /></bean>

三、Ioc容器对配置文件的读取支持:

    Spring支持对单个配置问价的读取,也支持对配置文件数组的读取,同时也支持若干文件的读取,但是文件命名需要有一定的规律。

//读取配置文件数组//String[] xmlFiles= new String[]{"applicationContext-beans.xml","applicationContext-editor.xml"};//BeanFactory  factory= new ClassPathXmlApplicationContext(xmlFiles);//读取单个配置文件//BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext.xml");//读取以applicationContext-开头命名的配置文件BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext-*.xml");


四、测试和访问:

有了上面的基础和配置,就可以对程序进行测试访问了:

public class InjectionTest extends TestCase {//工厂是线程安全的BeanFactory factory ;/** *类似servlet的初始化,只初始化一次 *在这里了放置工厂信息 */@Overrideprotected void setUp() throws Exception {System.out.println("------Factory Init");//读取配置文件数组//String[] xmlFiles= new String[]{"applicationContext-beans.xml","applicationContext-editor.xml"};//BeanFactory  factory= new ClassPathXmlApplicationContext(xmlFiles);//读取单个配置文件//BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext.xml");//读取以applicationContext-开头命名的配置文件factory= new ClassPathXmlApplicationContext("applicationContext-*.xml");}/** * 这里销毁工厂信息 */@Overrideprotected void tearDown() throws Exception {}public void testInjection1() {////这里必须从容器中取出,不能使用new,类似jndi的查找,否则,不会读出相关的配置Bean2 bean2 = (Bean2)factory.getBean("bean2");System.out.println("bean2.bean3.id=" + bean2.getBean3().getId());System.out.println("bean2.bean3.name=" + bean2.getBean3().getName());System.out.println("bean2.bean3.sex=" + bean2.getBean3().getSex());System.out.println("bean2.bean4.id=" + bean2.getBean4().getId());System.out.println("bean2.bean4.name=" + bean2.getBean4().getName());System.out.println("bean2.bean4.sex=" + bean2.getBean4().getSex());System.out.println("bean2.bean4.age=" + bean2.getBean4().getAge());System.out.println("bean2.bean5.password=" + bean2.getBean5().getPassword());}}

setUp()类似Servlet的初始化,只进行一次初始化,如果希望一些变量和工厂在程序推出的时候销毁可以放到tearDown()方法中进行处理。


五、关于Scope:

    Scope标签可以决定不同用户的Bean是否是同一个实例,故名思议,Scope是作用域范围的意思,它的常见的赋值有singleton和prototype。如果是prototype,我们可以理解成Bean的作用域仅限于每一个用户,而singleton则是所有用户共想用一个Bean实例。

    我们可以使用下面的程序进行简单的测试:

public void testInjection1(){//这里必须从容器中取出,不能使用new,类似jndi的查找,否则,不会读出相关的配置Bean1  bean1 = (Bean1)factory.getBean("bean1");Bean1  bean2 = (Bean1)factory.getBean("bean1");System.out.println(bean1==bean2);}


六、自动装配:

Spring提供了两种自动装配的方式:byType和byName。

byName:在配置文件中给beanid取名和引用它的类中的getset方法同名,并设置即可自动加载。

byType:根据Bean类中,属性的数据类型,自动加载。

如,Bean2中有对Bean3、4、5的引用,并设置的相关的get、set方法:

public class Bean2 {private Bean3 bean3;private Bean4 bean4;private Bean5 bean5;public Bean3 getBean3() {return bean3;}public void setBean3(Bean3 bean3) {this.bean3 = bean3;}public Bean4 getBean4() {return bean4;}public void setBean4(Bean4 bean4) {this.bean4 = bean4;}public Bean5 getBean5() {return bean5;}public void setBean5(Bean5 bean5) {this.bean5 = bean5;}}

如果使用byType自动装配:

在xsi:schemaLocation约束中添加:default-autowire="byType",在对Bean2的配置中就无需手动显示添加注入:

<bean id="bean2" class="com.bjpowernode.spring.Bean2" /><bean id="bean33" class="com.bjpowernode.spring.Bean3">……</bean> <bean id="bean44" class="com.bjpowernode.spring.Bean4">……</bean><bean id="bean55" class="com.bjpowernode.spring.Bean5">……</bean>

如果是byName: default-autowire="byName"  要求其他的bean的id受Bean2中的方法名的约束:

<bean id="bean2" class="com.bjpowernode.spring.Bean2" /><bean id="bean3" class="com.bjpowernode.spring.Bean3">……</bean> <bean id="bean4" class="com.bjpowernode.spring.Bean4">……</bean><bean id="bean5" class="com.bjpowernode.spring.Bean5">……</bean>


七、总结:

    Spring的Ioc容器对对象的注入提供了强大的支持,程序的灵活性往往都是通过对配置文件做活的,控制反转的思想很重要,在设计程序的时候应该借鉴这种设计思路。

    Ioc容器提供了多种读取配置文件的方式,另外,对对象的装载也提供了一些自动的默认机制,这种做法也是值得学习和借鉴的。

    Ioc还有一些其他的内容,如 default-lazy-init标签,BeanFactory、ApplicationContext等类和接口,这里就不再一一赘述。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 感冒总爱打喷嚏怎么办 一直流鼻涕怎么回事该怎么办 感冒一直流鼻涕该怎么办 婴儿一个月鼻塞怎么办 1岁婴儿感冒怎么办 轻微鼻塞感冒了怎么办 50天宝宝鼻塞怎么办 50天婴儿鼻塞怎么办 50天新生儿鼻塞怎么办 40天婴儿鼻塞怎么办 孩子感冒鼻子塞怎么办 月子里感冒了怎么办 宝宝感冒鼻塞严重怎么办 婴幼儿鼻塞有痰怎么办 感冒了浑身没劲怎么办 四个月宝宝鼻塞怎么办 四个月小孩鼻塞怎么办 小儿流清水鼻涕怎么办 小孩总是流鼻子怎么办 四个月小孩咳嗽怎么办 儿童流清水鼻涕怎么办 四个月婴儿发烧怎么办 宝宝体温36度怎么办 儿童感冒后鼻塞怎么办 儿童没感冒鼻塞怎么办 宝宝鼻塞怎么办3岁 儿童刚开始感冒鼻塞怎么办 婴儿感冒打喷嚏流鼻涕怎么办 宝宝感冒鼻涕多怎么办 一个多月的宝宝鼻塞怎么办 五个月宝宝鼻塞怎么办 4个月大婴儿鼻塞怎么办 四个月婴儿鼻塞怎么办 鼻炎晚上睡觉鼻塞怎么办 感冒了一直流鼻涕怎么办 感冒了鼻塞严重怎么办 两边鼻子都塞怎么办 感冒睡觉鼻子堵怎么办 孩子鼻炎流清水怎么办 小儿鼻涕流不停怎么办 老是单侧流鼻涕怎么办