spring-IOC进阶

来源:互联网 发布:数据挖掘最优算法 编辑:程序博客网 时间:2024/06/05 09:28

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

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

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

[java] view plain copy
  1. <span style="font-size:18px">private Date  dateValue;<span style="white-space:pre">        </span>  
  2.   
  3.   
  4. public Date getDateValue() {  
  5. <span style="white-space:pre">  </span>return dateValue;  
  6. }  
  7.   
  8. public void setDateValue(Date dateValue) {  
  9. <span style="white-space:pre">  </span>this.dateValue = dateValue;  
  10. }</span>  

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

    UtilDatePropertyEditor需要继承PropertyEditorSupport:

[java] view plain copy
  1. public class UtilDatePropertyEditor extends PropertyEditorSupport {  
  2.   
  3.     //将转换格式做成可配的  
  4.     private String pattern;  
  5.     @SuppressWarnings("unused")  
  6.     @Override  
  7.     public void setAsText(String text) throws IllegalArgumentException {  
  8.         System.out.println("--------UtilDatePropertyEditor.setAsText() ----"+text);  
  9.           
  10.         try {  
  11.             //日期转化  
  12.             Date date = new  SimpleDateFormat(pattern).parse(text);  
  13.             this.setValue(date);  
  14.               
  15.         } catch (ParseException e) {              
  16.             e.printStackTrace();  
  17.             throw new IllegalArgumentException(text);  
  18.         }                 
  19.           
  20.     }     
  21.     public void setPattern(String pattern) {  
  22.         this.pattern = pattern;  
  23.     }  
  24.       
  25. }  

说明:

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


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

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

[html] view plain copy
  1. <span style="font-size:18px"><beans xmlns="http://www.springframework.org/schema/beans"  
  2.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.          xmlns:aop="http://www.springframework.org/schema/aop"  
  4.          xmlns:tx="http://www.springframework.org/schema/tx"  
  5.          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  6.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
  7.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  8.     
  9.   <bean  id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">  
  10.     <property name="customEditors">  
  11.         <map>  
  12.             <entry key="java.util.Date">  
  13.                 <bean class="com.bjpowernode.spring.UtilDatePropertyEditor">  
  14.                     <property name="pattern"  value="yyyy-MM-dd"></property>  
  15.                 </bean>  
  16.             </entry>  
  17.         </map>  
  18.     </property>  
  19.   
  20.   </bean>   
  21.    
  22. </beans></span>  

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

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

[html] view plain copy
  1. <span style="font-size:18px"><bean  id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">  
  2.   <property name="customEditors">  
  3.     <map>  
  4.         <entry key="java.util.Date" value-ref="customDatePropertyConvertor">                    
  5.         </entry>  
  6.     </map>  
  7.   </property>  
  8.   
  9.  </bean>  
  10.  <!-- 外部可以使用这个转换器  -->  
  11.  <bean id="customDatePropertyConvertor" class="com.bjpowernode.spring.UtilDatePropertyEditor">  
  12.     <property name="pattern"  value="yyyy-MM-dd"></property>  
  13.  </bean></span>  

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

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

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

[html] view plain copy
  1. <span style="font-size:18px"><bean id="bean1" class="com.bjpowernode.spring.Bean1">  
  2.           
  3.     <property name="map">  
  4.         <map>  
  5.             <entry key="k1" value="v1"></entry>  
  6.             <entry key="k2" value="v2"></entry>  
  7.         </map>  
  8.     </property>  
  9.   
  10.     <property name="dateValue">  
  11.         <value> 2013-09-28</value>  
  12.     </property>  
  13.   
  14. </bean></span>  


二、代码复用策略:

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

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

1、将公共属性放到一个抽象bean中,为了管理的方便,这里单独放到applicationContext-common.xml文件中:

[html] view plain copy
  1. <span style="font-size:18px"><?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  7.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
  8.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">  
  9.   
  10.     <bean abstract="true" id="abstractbean" name="beancommon">  
  11.         <property name="id" value="111" />  
  12.         <property name="name" value="任我行" />  
  13.         <property name="sex" value="男" />  
  14.     </bean>  
  15.       
  16.     <bean id="bean3" class="com.bjpowernode.spring.Bean3" parent="abstractbean" />  
  17.   
  18.       
  19. </beans></span>  


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

[html] view plain copy
  1. <span style="font-size:18px"><bean id="bean4" class="com.bjpowernode.spring.Bean4" parent="abstractbean">       
  2.     <property name="age" value="25" />  
  3. </bean></span>  


注意:

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

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

[html] view plain copy
  1. <span style="font-size:18px"><bean id="bean2" class="com.bjpowernode.spring.Bean2">  
  2.     <property name="bean3" ref="bean3" />  
  3.     <property name="bean4" ref="bean4" />  
  4.     <property name="bean5" ref="bean5" />  
  5. </bean></span>  

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

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

[java] view plain copy
  1. <span style="font-size:18px">//读取配置文件数组  
  2. //String[] xmlFiles= new String[]{"applicationContext-beans.xml","applicationContext-editor.xml"};  
  3. //BeanFactory  factory= new ClassPathXmlApplicationContext(xmlFiles);  
  4.           
  5. //读取单个配置文件  
  6. //BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext.xml");  
  7.           
  8. //读取以applicationContext-开头命名的配置文件  
  9. BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext-*.xml");</span>  


四、测试和访问:

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

[java] view plain copy
  1. <span style="font-size:18px">public class InjectionTest extends TestCase {  
  2.   
  3.     //工厂是线程安全的  
  4.     BeanFactory factory ;  
  5.       
  6.     /** 
  7.      *类似servlet的初始化,只初始化一次 
  8.      *在这里了放置工厂信息 
  9.      */  
  10.     @Override  
  11.     protected void setUp() throws Exception {  
  12.         System.out.println("------Factory Init");  
  13.           
  14.         //读取配置文件数组  
  15.         //String[] xmlFiles= new String[]{"applicationContext-beans.xml","applicationContext-editor.xml"};  
  16.         //BeanFactory  factory= new ClassPathXmlApplicationContext(xmlFiles);  
  17.           
  18.         //读取单个配置文件  
  19.         //BeanFactory factory= new ClassPathXmlApplicationContext("applicationContext.xml");  
  20.           
  21.         //读取以applicationContext-开头命名的配置文件  
  22.         factory= new ClassPathXmlApplicationContext("applicationContext-*.xml");  
  23.                   
  24.     }  
  25.   
  26.     /** 
  27.      * 这里销毁工厂信息 
  28.      */  
  29.     @Override  
  30.     protected void tearDown() throws Exception {  
  31.           
  32.     }  
  33.   
  34.       
  35.     public void testInjection1() {  
  36.         ////这里必须从容器中取出,不能使用new,类似jndi的查找,否则,不会读出相关的配置  
  37.         Bean2 bean2 = (Bean2)factory.getBean("bean2");  
  38.         System.out.println("bean2.bean3.id=" + bean2.getBean3().getId());  
  39.         System.out.println("bean2.bean3.name=" + bean2.getBean3().getName());  
  40.         System.out.println("bean2.bean3.sex=" + bean2.getBean3().getSex());  
  41.         System.out.println("bean2.bean4.id=" + bean2.getBean4().getId());  
  42.         System.out.println("bean2.bean4.name=" + bean2.getBean4().getName());  
  43.         System.out.println("bean2.bean4.sex=" + bean2.getBean4().getSex());  
  44.         System.out.println("bean2.bean4.age=" + bean2.getBean4().getAge());  
  45.         System.out.println("bean2.bean5.password=" + bean2.getBean5().getPassword());  
  46.     }  
  47.   
  48. }</span>  

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


五、关于Scope:

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

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

[java] view plain copy
  1. <span style="font-size:18px">public void testInjection1(){  
  2.           
  3.     //这里必须从容器中取出,不能使用new,类似jndi的查找,否则,不会读出相关的配置  
  4.     Bean1  bean1 = (Bean1)factory.getBean("bean1");  
  5.     Bean1  bean2 = (Bean1)factory.getBean("bean1");  
  6.           
  7.     System.out.println(bean1==bean2);         
  8.       
  9. }</span>  


六、自动装配:

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

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

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

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

[java] view plain copy
  1. public class Bean2 {  
  2.   
  3.     private Bean3 bean3;  
  4.     private Bean4 bean4;  
  5.       
  6.     private Bean5 bean5;  
  7.   
  8.     public Bean3 getBean3() {  
  9.         return bean3;  
  10.     }  
  11.   
  12.     public void setBean3(Bean3 bean3) {  
  13.         this.bean3 = bean3;  
  14.     }  
  15.   
  16.     public Bean4 getBean4() {  
  17.         return bean4;  
  18.     }  
  19.   
  20.     public void setBean4(Bean4 bean4) {  
  21.         this.bean4 = bean4;  
  22.     }  
  23.   
  24.     public Bean5 getBean5() {  
  25.         return bean5;  
  26.     }  
  27.   
  28.     public void setBean5(Bean5 bean5) {  
  29.         this.bean5 = bean5;  
  30.     }  
  31.       
  32.       
  33.   
  34. }  

如果使用byType自动装配:

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

[html] view plain copy
  1. <bean id="bean2" class="com.bjpowernode.spring.Bean2" />  
  2.           
  3. <bean id="bean33" class="com.bjpowernode.spring.Bean3">  
  4.     ……  
  5. </bean>   
  6.   
  7. <bean id="bean44" class="com.bjpowernode.spring.Bean4">  
  8.     ……  
  9. </bean>  
  10.   
  11. <bean id="bean55" class="com.bjpowernode.spring.Bean5">  
  12.     ……  
  13. </bean>  

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

[java] view plain copy
  1. <bean id="bean2" class="com.bjpowernode.spring.Bean2" />  
  2.           
  3. <bean id="bean3" class="com.bjpowernode.spring.Bean3">  
  4.     ……  
  5. </bean>   
  6.   
  7. <bean id="bean4" class="com.bjpowernode.spring.Bean4">  
  8.     ……  
  9. </bean>  
  10.   
  11. <bean id="bean5" class="com.bjpowernode.spring.Bean5">  
  12.     ……  
  13. </bean>  


七、总结:

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

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

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

0 0
原创粉丝点击