ioc

Posted on 2009-06-05 14:22 阅读(194) 评论(0)  编辑  收藏

一、IOC的概念
        Inversion of control 控制反转;
        以前: 对象的协作关系A类自己来负责;
            A do() ---> B f1()
                   ---> C f2()
            do(){
                new B().f1();
                new C().f2();
            }
            对象A负责建立与其协作对象的关系;
            问题:
                1)对象协作关系的建立与业务本身的逻辑纠缠在一起;
                2)协作关系也是不容易维护的;(B, C发生改变)

         现在: 对象的协作关系容器来负责;
            
             A do() ---> IB <---B f1()
                    ---> IC <---C f2()
             setIB(B)
             setIC(C)
           对象不再负责建立与协作对象的关系, 由容器来负责对象的协作关系;       
            
       控制: 指对象的协作关系由谁来建立;
       反转: 原来由对象自己调用的变成了容器调用;
      
       好处: 代码更好维护, 协作关系不需要考虑了;
                                      对象依赖于接口, 协作对象发生改变以后, 不需要改变;
       控制反转又叫依赖注入: 将对象的协作关系由容器来注入;                               
       
二、 基本的容器与IOC的使用
1, spring-framework-2.0.6-with-dependencies
      MyEclipse 自带的有jar包,但是会有一些问题;

      我们再创建自己的user库: spring2_lib:
      需要三个地方的包:
      spring framework/dist/spring.jar
                       lib/jakarta-commons/*.jar
                       lib/cglib/*.jar

      新建工程springdev 右击, myeclipse-- add spring capabilities--- add user libriay--spring2_lib

      接口: Greeter
            package ioc1;

            public interface Greeter {
                   public String sayHello();
            }
      实现类: GreeterImpl
            package ioc1;

            public class GreeterImpl implements Greeter{
            private String user;
            //提供一个set方法, 可以注入
            public void setUser(String user) {
               this.user = user;
            }
           
            public String sayHello() {
              
               return "你好 " +user;
            }
            }

        配置文件: applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
            <bean id="greeter" class="ioc1.GreeterImpl">
              <property name="user"><!-- 属性名字 -->
        <value>zhangsan</value>
              </property>
            </bean>
        </beans>

        测试类:Test
            import org.springframework.beans.factory.BeanFactory;
            import org.springframework.beans.factory.xml.XmlBeanFactory;
            import org.springframework.core.io.ClassPathResource;
            import org.springframework.core.io.Resource;
           
            public class Test {
            public static void main(String[] args) {
               //配置文件的路径
               Resource rs=new ClassPathResource("/ioc1/applicationContext.xml");
               BeanFactory bf=new XmlBeanFactory(rs);
               Greeter gt=(Greeter) bf.getBean("greeter");//配置文件中id的名字
               System.out.println(gt.sayHello());
              
            }
            }

2, IOC的类型:
         1) set 方式来注入:
                <property name=””></property>
                其中,name属性的取值依setter方法名而定
                对于基本类型,spring容器会自动做类型转换,以便赋值;

         2)构造器的方式来注入;
                <constructor-arg index=””></ constructor-arg>
                其中,index表示构造方法中的参数位置(第一个参数索引为0)

         3)实现特定的接口来注入,
                这种方式已经不采用了,因为业务对象会依赖框架的特定接口;
                " 侵入式 "方案;

    注入的类型:
        1)八种基本类型+String ;
        2)对象
        3)集合: list, set , map , properties
        4)null

3, Spring 容器 :
      用于实例化对象, 然后赋值或者装配, 生命周期管理的一种类;
      容器的种类:
            BeanFactory: 1)所有容器的父接口, 组件的生成和组装;
                         2)提供了基本的IOC的功能;
                         3)一个实现: XmlBeanFactory ,
                           需要提供一个Resource的实例给XmlFactory, Resource对象来包装配置文件;
                         4)getBean(String)方法,返回一个装配好的对象;
                         5)在默认情况下返回的对象都采用的单例模式;
                         6)直到调用getBean方法时, 才会实例化并且装配对象;
                         实例化 -- 构造对象, 给属性赋值 -- 装配/注入 ;

            ApplicationContext: Spring的上下文, 也是一个容器, 是BeanFactory的子接口;
                                增强了BeanFactory, 提供了事件处理, 国际化,复杂的生命周期管理;
                                一般情况下用ApplicationContext, 而不用BeanFactory;
                                实现类:
                                     ClassPathXmlApplicationContext: 依据classpath查找配置文件;
                                     容器初始化的时候会预先实例化单例的对象; 可以配置, 有的采用单例有的不用; 三、set 方式注入:
<1>. 基本类型的注入:
      注入简单类型: 八种基本类型+String
      方式: id是bean的id号, 唯一的; class是bean类的全路径;
      <bean id="" ,class="">     
            <property name=""> <!--属性名, set方法去掉set并将首字母小写后的名字 -->     
                <value>属性值</value>
            </property>     
     </bean>                
     对于基本类型, 会自动转换数据类型; 跟序列化的意思差不多;
      用ApplicationContext 容器写测试类:
        ApplicationContext ctx=new ClassPathXmlApplicationContext("/ioc1/applicationContext.xml");
        Greeter gt2=(Greeter) ctx.getBean("greeter");
        Greeter gt3=(Greeter) ctx.getBean("greeter");
         System.out.println(gt2.sayHello());
        //测试单例模式;true
        System.out.println(gt2==gt3);

<2>. 对象类型的注入:
     1) <ref local> 要注入的对象在同一个配置文件中;
      2) <ref bean> 要注入的对象可以分散在其他的配置文件中;
      3) 将要注入的bean类的配置信息直接嵌入到bean类中;(有点象内部类)
         不让客户端直接用getBean方式获得,该对象只被注入的对象使用;

例子1:
        实现类:
        public class OderServiceImpl implements OrderService{
     private SomeBean sb; //最好用接口
}

        ============================第一种:<ref local>=================================
配置文件1: <ref local>
                    使用local则定义的两个类必须出现在同一个配置文件中
        <!-- 第一个bean -->
        <bean id="otherBean" class="IOC.pm.set.Class.OtherBean">
        <property name="str"><!-- 属性名字 -->
           <value>someinfo</value>
        </property>
        </bean>
       
        <!-- 第二个bean -->
        <bean id="someBean" class="IOC.pm.set.Class.SomeBean">
        <property name="ob">
           <ref local="otherBean"/> //另外一个bean的id;
        </property>
        </bean>
      
        ===========================第二种:嵌套==================================
        或者2: 嵌到一起: 被嵌套的bean就不能够使用getBean()来返回了;
               使用嵌套定义的两个类必须出现在同一个配置文件中
         <bean id="someBean" class="IOC.pm.set.Class.SomeBean">
   <property name="ob">
                 <!--这样的话ohterBean只能被someBean调用 -->
           <bean id="otherBean" class="IOC.pm.set.Class.OtherBean">
                        <property name="str1"><!-- 属性名字 -->
                           <value>tarena</value>
     </property>
    </bean>
   </property>
</bean>

        ============================第三种:<ref bean>==================================
        或者3: <ref bean>: 功能最强大的搜索多个配置文件;
                 加一个配置文件: otherContext.xml 放someBean的配置;
                 applicationContext.xml中 <ref bean="otherBean"/>
                 测试类中: 写成一个字符串数组;
                 ApplicationContext ctx=new ClassPathXmlApplicationContext(
                               new String[]{"/ioc2/applicationContext.xml","/ioc2/other-config.xml.xml"});

   <3>. 集合的注入: (看老师的示例; )
         List: 可重复的,有序
                可以存放字符串,对象, 以及集合;
                <property name="list">
           <list>
            <value>String1</value>
            <value>String2</value>
           </list>
         </property>

         Set: 不重复, 无序
                可以存放字符串,对象, 以及集合;
                <property name="set">
    <set>
     <value>String1</value>
     <value>String1</value>
    </set>
   </property>

         Map:Key(只能用String), value 键值对;
                <property name="map">
    <map>
     <entry key="key1"><!-- 用key来存放key的值,用value来存放value值 -->
      <value>value1</value>
     </entry>
     <entry key="key2">
      <value>value2</value>
     </entry>
    </map>
   </property>
  
         Properties: key(String),value(String) 键值对
        
                <property name="properties">
    <props>
     <prop key="key11">value11</prop>
     <prop key="key22">value22</prop>
    </props>
   </property>
四、构造器的方式注入:      
              <1>. <constructor-arg>
   <value>基本类型</value>
</constructor-arg>
             <2>. <constructor-arg>
   <ref bean=""></ref>
</constructor-arg>
    <bean id="someBean" class="ioc4.SomeBean">
   <constructor-arg index="1"><!--参数的顺序可以改变,下标从0开始 -->
     <value>String1</value>
   </constructor-arg>
   <constructor-arg index="0">
     <value>String2</value>
   </constructor-arg>
</bean>

构造器注入和set方式注入比较:
             用构造器注入:如果要注入的对象,属性不是特别多,并且属性值一定要被注入后才能来使用;
             其他情况用set方式注入;
                                 
五、IOC的特例 ;

    1, 自动装配, 让容器依据某种规则,自动的对组件实施装配;
             在bean中:
              autowire=""
                   <1>. byName: 匹配属性的名字与bean的id号进行匹配; 找set方法;

                       someBean中有一个ob的属性:
                        <bean id="ob" class="ioc6.OtherBean">
                <property name="str1">
                 <value>String1</value>
                </property>
                </bean>
                <bean id="someBean" class="ioc6.SomeBean" autowire="byName">
                   <property name="str1">
                    <value>String1</value>
                   </property>
                </bean>
               
                   <2>. byType: 寻找配置文件, 匹配的属性类型与bean一致; 找set方法;
                                 上面例子改成byType 也是正确的, 并且ob可以改为别的名字;
                                 如果在配置文件中找到符合条件的bean的个数超过一个,会报错;

                   <3>. constructor: 匹配构造器,看构造器的参数类型和配置文件bean的类型是否一致,
                                     一致就成功,否则报错;
                                     匹配个数超过一个,也报错;
                                     提供一个构造器;

                   <4>. autodetect: 自动检测, 先构造器, 再set方法(也就是可以set方法和构造方法可以同时使用);

              自动从配置文件中寻找对应的bean的名字;
              注意:手动装配会覆盖自动装配的策略;
             
          问题:
                    1)自动装配用的很少, 配置文件中,bean的关系不清晰, 易出错;
                       在建立原型的时候, 快速搭建, 真正开发的时候, 一般手动配置;
                    2)自动装配和手动装配配合在一起使用; 手动可以覆盖自动的;
                    3)自动装配搭配一个装配检查; 属性先检查, 出错后就不再进行了;
                     dependency-check=""
                            simple :只检查基本类型属性是否装配成功;
                            objects:只检查Object类型是否装配成功;
                            all:全检查;
                     既可以和自动装配一起使用, 也可以单独用来检查是否装配成功;

          自动装配的使用情况:
                   1,构建系统原形;
                   2,与dependency-check=""配合使用;
                   3,手动装配会和自动装配要配合使用;             


     2, 用工厂的方式创建对象: 静态工厂, 实例工厂;
          原因是: 很多对象不方便采用配置文件去装配;
          如: 获得数据库连接, 可以写一个ConnectionFactory, getConnection方法
          静态工厂类, 静态方法, getBean("connection")就可以得到连接;
                public static Car createCar(){// 静态工厂,静态方法
      return new Car();
   }
                <bean id="car" class="ioc5.CarFactory" factory-method="createCar" />
                Car car=(Car) ctx.getBean("car");
   System.out.println(car);
          实例工厂: 指工厂实例化后才能使用,
                public Car createCar(){// 必须是实例方法
      return new Car();
   }
               <bean id="carFactory" class="ioc5.CarFactory" />
       <bean id="car" factory-bean="carFactory"   factory-method="createCar" />

    3,继承关系:
         <bean id="abstractBean" class="day02.ioc7.SomeBean" abstract="true">
    <property name="str1">
     <value>string1</value>
    </property>
    <property name="num">
     <value>20</value>
    </property>
   </bean>
   <!-- 继承关系 -->
   <bean id="someBean" parent="abstractBean">
    <property name="num">
     <value>30</value>
    </property>
         </bean>
       
    得到的bean不想用单例时, 在bean标签上加 Scope=singleton/prototype


    装配中的其它情况:
    
   单例:scope=""
        singleton,prototype
      
   初始化与销毁: init-method,destroy-method


只有注册用户登录后才能发表评论。


网站导航:
 

posts - 40, comments - 9, trackbacks - 0, articles - 9

Copyright © 希