现在的位置: 首页 > 综合 > 正文

Spring–IOC容器详解

2018年05月21日 ⁄ 综合 ⁄ 共 8882字 ⁄ 字号 评论关闭
文章目录

 

        Spring作为一个在java界广泛使用且评价颇高的一个开源框架,给我们提供了好多的功能,极大的方便了我们的开发。此处我介绍IOC容器和AOP概念。

        IOCInversion of Control)控制反转:本来是由应用程序管理的对象之间的依赖关系,现在交给了容器管理,这就叫控制反转,即交给了IOC容器,SpringIOC容器主要使用DI方式实现的。不需要主动查找,对象的查找、定位和创建全部由容器管理。

       通俗点说就是不创建对象。以前我们要调用一个对象的方法,首先要new一个对象。但使用IOC容器,在代码中不直接与对象连接,而是在配置文件中描述要使用哪一个对象。容器负责将这些联系在一起。

       IOC容器的对象实例化是通过配置文件来实现的。术语上这叫做注入。注入有两种形式,采用构造方法注入和采用setter注入。具体的注入形式如下

采用set方法注入,给属性添加一个set方法,并对其进行赋值

publicclass UserManagerImplimplements UserManager
{

    private UserDaouserDao;

    publicvoid setUserDao(UserDao userDao) {

        this.userDao = userDao;

    }

}

采用构造方法注入,在构造方法中对属性进行赋值

publicclass UserManagerImplimplements UserManager
{

    private UserDaouserDao;

    public UserManagerImpl(UserDao userDao) {

        this.userDao = userDao;

    }

}

配置文件:

<beanid="userManager"class="com.bjpowernode.spring.manager.UserManagerImpl">

     <propertyname="userDao"ref="usrDao4Oracle"/>

  </bean>

配置文件:

<beanid="userManager"class="com.bjpowernode.spring.manager.UserManagerImpl">

    <constructor-argref="userDao4Mysql"/>

</bean>

set注入特点:

        与传统的JavaBean的写法更相似,程序员更容易理解、接受,通过setter方式设定依赖关系显得更加直观、明显;

        对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致死你功能下降。而使用设置注入,则避免这下问题;

       尤其在某些属性可选的情况下,多参数的构造器更加笨拙。

 

构造方法注入特点:

       构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。

<p LINE-HEIGHT= 25px" align="left">       对于依赖关系无须变化的Bean,构造注入更有用处;因为没有setter方法,所有的依赖关系全部在构造器内设定,因此,不用担心后续代码对依赖关系的破坏。

      依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则;

 

        建议采用以设置注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设置注入。

       此处我们说的普通属性的注入,但是还有一些列表,数组,map等类型的变量。我们看一下他们的注入形式:

  1. <bean id="bean1" class="com.bjpowernode.spring.Bean1">  
  2.         <property name="strValue" value="Hello_Spring"/>  
  3.           
  4.         <!--  
  5.         <property name="intValue" value="123"/> 
  6.          -->  
  7.         <property name="intValue">  
  8.             <value>123</value>  
  9.         </property>  
  10.           
  11.         <property name="listValue">  
  12.             <list>  
  13.                 <value>list1</value>  
  14.                 <value>list2</value>  
  15.             </list>  
  16.         </property>  
  17.         <property name="setValue">  
  18.             <set>  
  19.                 <value>set1</value>  
  20.                 <value>set2</value>  
  21.             </set>  
  22.         </property>  
  23.         <property name="arrayValue">  
  24.             <list>  
  25.                 <value>array1</value>  
  26.                 <value>array2</value>  
  27.             </list>  
  28.         </property>  
  29.         <property name="mapValue">  
  30.             <map>  
  31.                 <entry key="k1" value="v1"/>  
  32.                 <entry key="k2" value="v2"/>  
  33.             </map>  
  34.         </property>  
  35.         <property name="dateValue" value="2009年12月14日" />  
  36.     </bean>  

        spring中并不是所有类型的编辑器都实现好了,有些类型比如时间他就没有实现。需要我们自己去定义。如何自定义属性编辑器呢?首先,要继承PropertyEditorSupport类,然后覆盖setAsText()方法,最后将自定义的属性编辑器注入到spring中

  1. public class UtilDatePropertyEditorextends PropertyEditorSupport {  
  2.   
  3.     private Stringpattern;  
  4.   
  5.     @Override  
  6.   
  7.     publicvoid setAsText(String text)throws IllegalArgumentException {  
  8.   
  9.         System.out.println("---UtilDatePropertyEditor.setAsText()--->" + text);  
  10.   
  11.         try {  
  12.   
  13.             Date date = new SimpleDateFormat(pattern).parse(text);  
  14.   
  15.             this.setValue(date);  
  16.   
  17.         } catch (ParseException e) {  
  18.   
  19.             e.printStackTrace();  
  20.   
  21.             thrownew IllegalArgumentException(text);  
  22.   
  23.         }  
  24.   
  25.     }  
  26.   
  27.     publicvoid setPattern(String pattern) {  
  28.   
  29.         this.pattern = pattern;  
  30.   
  31.     }     
  32.   
  33. }  

       这里pattern匹配形式,我们采用的是set注入。配置文件中实现为:

  1. <bean id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">  
  2.         <property name="customEditors">  
  3.             <map>  
  4.                 <entry key="java.util.Date">  
  5.                     <bean class="com.bjpowernode.spring.UtilDatePropertyEditor">  
  6.                         <property name="pattern" value="yyyy年MM月dd日"/>  
  7.                     </bean>  
  8.                 </entry>  
  9.             </map>  
  10.         </property>  
  11.     </bean>  

        从上面可以看出,配置文件中每一个类用bean标签来标识,属性用property来标识。如果属性多的话,配置文件也会很繁杂。有没有某种情况能够减少配置文件的一些设置呢?确实是可以的,如果几个bean都有相同的属性,那这些属性是可以抽象出来的。比如:

  1. <bean id="AbstractBean"abstract="true">  
  2.         <propertynamepropertyname="id"value="100"/>  
  3.         <propertynamepropertyname="name"value="zhangsan"/>  
  4.         <propertynamepropertyname="sex"value="nan"/>  
  5. </bean>      
  6. <beanidbeanid="bean3"class="com.bjpowernode.spring.Bean3"parent="AbstractBean"/>  
  7. <beanidbeanid="bean4"class="com.bjpowernode.spring.Bean4"parent="AbstractBean">  
  8.      <propertynamepropertyname="age">  
  9.           <value>90</value>  
  10.      </property>  
  11. </bean>  

         bean3,bean4中有相同的属性,id,name,sex,则可以将其抽象出一个抽象bean,然后,在具体bean中指定其parent标签为抽象bean。

        我们都知道正则表达式,用一个统一的格式表示多种不同的字符。在IOC中也有类似的功能。有得时候某个对象中包含其他对象的属性。如果,这些属性名称name间或者类型(具体的包名类名)有某种关系的话,是可以不用显示调用的。IOC容器自动就回去查找。如:

  1. <beans ...  
  2.            default-autowire="byName"  
  3.            >  
  4.   
  5.     <!--   
  6.     <bean id="bean2" class="com.bjpowernode.spring.Bean2">  
  7.         <property name="bean3" ref="bean3"/>    
  8.         <property name="bean4">  
  9.             <ref bean="bean4"/>  
  10.         </property>  
  11.         <property name="bean5" ref="bean5"/>  
  12.     </bean>  
  13.     -->  
  14.   
  15.     <bean id="bean2" class="com.bjpowernode.spring.Bean2"/>  

  1. <beans ...  
  2.            default-autowire="byType"  
  3.            >  
  4.   
  5.     <!--   
  6.     <bean id="bean2" class="com.bjpowernode.spring.Bean2">  
  7.         <property name="bean3" ref="bean3"/>    
  8.         <property name="bean4">  
  9.             <ref bean="bean4"/>  
  10.         </property>  
  11.         <property name="bean5" ref="bean5"/>  
  12.     </bean>  
  13.     -->  
  14.   
  15.     <bean id="bean2" class="com.bjpowernode.spring.Bean2"/>  
  16.   
  17.     <bean id="bean322" class="com.bjpowernode.spring.Bean3">  
  18.         <property name="id" value="100"/>  
  19.         <property name="name" value="zhangsan"/>  
  20.         <property name="sex" value="nan"/>  
  21.     </bean>  

        IOC容器实现的bean配置与我们在代码中new实例达到的效果是一样的。那我们实例化的时候,可以采用单例模式,只保证有一个实例在运行,也可以多个实例运行。IOC容器中有这种配置吗?当然有,那就是bean的scope作用域。singleton默认值,每次调用getBean()向IOC容器中取得的对象是相同的。即单例。而prototype,则是每次调用getBean()向IOC容器中取得对象是不相同的。即相当于普通的实例化。
 
<bean
id
="bean1"class="com.bjpowernode.spring.Bean1"scope="prototype"/>

或者

<bean
id
="bean1"class="com.bjpowernode.spring.Bean1"scope="singleton"/>

         通过IOC控制反转,大量减少了Factory和Singleton的数量,使代码层次更加清晰。Spring的IOC容器是一个轻量级的容器,没有侵入性,不需要依赖容器的API,也不需要实现一些特殊接口。而一个合理的设计最好尽量避免侵入性。减少了代码中的耦合,将耦合推迟到了配置文件中,发生了变化也更容易控制。

抱歉!评论已关闭.