java _IOC


原文:http://blog.chinaunix.net/uid-24337578-id-177319.html



1.IOC的本质
   Ioc(Inversion of Control)中文译名控制反转
   IoC意味着将设计好的类交给系统去控制,而不是在类的内部控制。这就称为控制反转。IOC要解决的就是程序之间调用的一个问题。基于IOC原理, 可衍生出不同种类的模式与框架。这些模式与框架可提供一种新的机制管理业务对象及其依赖关系, 可以减少“粘合”代码, 使依赖外置化, 可以在统一的地方管理依赖, 从而有效地降低软件开发问题的复杂度、减小维护的代价。

 


2.不用IOC面临的问题
   比如,现在准备做一个业务操作类service,其代码实现如下:
   Interface IService{
      go();
   }

   public Service implements IService{
      public void go() {
         ...
      }
   }
实现Service实例化的几种方式及分析:
第一种方式
   Service service = new Service();
   这样个方式非常直观, 但是维护性差,不能保证目前设计的正确性,如果在以后的使用中才发现错误那么就要很费劲的修改源代码。

第二种
   IService service = new Service();
   这样的方式一定程序上解决了和具体实现类耦合问题,但是还是面临着新的问题:
   如果实现这个接口的具体类的类名变了,怎么办?
   比如:现在2.0版本,Service.java变成了Service2.java
   还是必须修改源代码。能不能当具体实现类的类名变化时,也不用修改源代码?那就得用第三种方式

第三种
   IService service = ServiceFactory.Create();
   工厂模式, 在Ioc容器出现以前被广泛应用于各种项目中, 甚至有这样的说法, 没有工厂的项目就不是好项目, 虽然有点偏激但却有一定道理. 以ServiceFactory.Create()来推迟了类的实例化, 这样看起来无论声明和实例化都脱离了对具体类的依赖, 但具体的类终究还是要实例化。
   方案一
   直接return new Service(); 这效果和上一种方式没啥本质区别了, 到头来换了具体实现类还得修改代码.
   方案二
   读取配置文件中的信息, 用反射来实例化组件, 彻底的把具体实现类的信息从代码中剥离到了配置文件中, 更换具体实现类时仅需要修改配置文件. 接口终于完全的发挥出了他的威力, 但这种方式造成大量不统一的工厂产生, 而具体实现类之间常会有着各种不同的依赖关系, 使得工厂的复杂度大大增加, 实现与管理这些工厂又成了新的问题, Ioc容器就在这样的需求下出现了.

第四种
   IService service= CommonService.Container.Resolve<IService>();
   看起来和通过工厂获取实例差不多, 但 CommonService.Container是简易包装的一个Ioc容器,现在只需要知道从容器中来获取类的实例. Ioc容器是一个可复用的类管理工具, 可以很方便的引入到项目中, 通过向其中简单的注册需要被管理的类后, 便能管理类和他们之间的关系. 这样避免了大量的工厂出现, 更进一步的减少了代码量, 提高了项目的扩展维护性.

 

3.控制反转的实现

 

    IoC可以用不同的方式来实现。其主要实现方式有两种:

<1>依赖查找(Dependency Lookup):容器提供回调接口和上下文环境给组件。EJB和Apache Avalon都使用这种方式。(现在用的不多了)

 

<2>依赖注入(Dependency Injection):组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。后者是时下最流行的IoC类型,其又有接口注入(Interface Injection),设值注入(Setter Injection)和构造子注入(ConstructorInjection)。

依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露JavaBean的setter方法或者带参数的构造子或者接口,使容器可以在初始化时组装对象的依赖关系。

与依赖查找方式相比,主要优势为:

<1>查找定位操作与应用代码完全无关。

<2>不依赖于容器的API,可以很容易地在任何容器以外使用应用对象。

<3>不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器。

所以不会用依赖查找

 

 

4.依赖注入


    IOC并不能清晰地解释类与类之间依赖的解耦关系,软件界的泰斗级人物Martin Fowler提出了DI(依赖注入:Dependency Injection)的概念,即将客户类对接口实现类的依赖关系由第三方(容器或协作类)注入,以移除客户类对具体接口实现类的依赖。
    我们使用抽象接口来隔离使用者和具体实现之间的依赖关系,但是不管再怎么抽象,最终还是要创建具体实现类的实例,这种创建具体实现类的实例对象就会造成对于具体实现的依赖,为了消除这种创建依赖性,需要把依赖移出到程序的外部(比如配置文件)。
    使用依赖注入后,这些类完全是基于抽象接口编写而成的,所以可以最大限度地适应需求的变化。
4.1 举例说明
现有一个服务接口,只有一个行为,

     public interface Iprint {
       public void go();
}
IprintSer类是接口Iprint的实现者
    public interface Iprint {
       public void go();
}
Test类想调用这个服务,最原始的方法:
   public Consumer{
      IprintSer iprint=new IprintSer();
      iprint.go();     



  

4.2 构造子注入
通过构造函数,将接口的具体实现类注入进来。代码如下
    public class Custom {
    private IprintSer service = null;

    public Custom(IprintSer service) { 
     this.service=service;
  // TODO Auto-generated constructor stub
     }

       public  void doSomething() {
           service.go();
         }
     }

调用过程如下
    IprintSer service=new IprintSer();
     Custom custom=new Custom(service);
     custom.doSomething();

4.3 Setter方法注入
    private IprintSer service = null;

    public void SetCustom(IprintSer service)

     { 
          this.service=service;
      // TODO Auto-generated constructor stub
      }

      public  void doSomething() {
         service.go();
      }

调用过程如下
     IprintSer service=new IprintSer();
     Custom custom=new Custom();
     custom.SetCustom(service);
     custom.doSomething();
4.4接口注入
接口注入是指将客户类所有注入的方法抽取到一个接口中,客户类通过实现这一接口提供注入的方法。为了采取接口注入的方式,需要声明一个额外的接口:
    public interface Injectable{
       void injectService(IService service);
    }
Consumer类通过继承Injectable接口注入
    public Consumer implements Injectable{
      private IService service = null;

      public injectService(IService service){
         this.service=service;
      }

      public void doSomething() {
         service.go();
      }
    }
调用过程如下:
    Service service=new Service();
    Consumer consumer=new Consumer();
    consumer.injectService(service);
    consumer.doSomething();

由于通过接口注入需要额外声明一个接口,增加了类的数目,而且它的效果和属性注入并无本质区别,因此我们不提倡这种方式。

4.5类与类之间依赖的管理

   类与类之间的依赖关系实现了解耦,但是类的实例化和类与类之间的注入依然是存在的,只是这个工作被延后并且由另外的类来完成,我们把管理这些类的实例化和对类与类之间关系进行管理的模块称之为第三方容器。
    这种容器帮助我们完成类的初始化和装配工作,让我们从这些底层的实现类实例化,依赖关系的装配中脱离出来,专注于更有意思的业务代码的编写工作,那确实是挺惬意的事情。Spring就是这样一个容器,它通过配置文件描述类之间的依赖关系,下面是Spring配置文件的对以上实例进行配置的样式代码:

    <beans>
        <bean id="myservice" class="com.Service"></bean>
        <bean id="consumer" class="com.Consumer">
            <property name="service"><ref bean="myservice"/></property>
        </bean>
    </beans>

    通过new XmlBeanFactory(“beans.xml”)等方式即可启动容器,在容器启动时,Spring根据配置文件的描述信息,通过Java的反射机制自动实例化Bean并完成依赖关系的建立,从容器中即可返回准备就绪的Bean实例,以待后续的使用。

 

<think>好的,我现在需要回答用户关于Spring框架中IOC参数的问题。首先,用户提到的IOC参数可能指的是Bean的作用域、配置参数或依赖注入相关的参数。我需要结合提供的引用内容来整理答案。 根据引用[1],Bean的作用域是IOC容器管理Bean实例的重要参数,如singleton和prototype。引用[2]展示了通过XML配置获取Bean的实例,而引用[3]解释了IOC和DI的基本概念,其中提到DI负责注入属性。因此,IOC参数可能涉及作用域、配置方式(XML或注解)、依赖注入的参数设置等。 接下来,我需要组织这些信息,确保结构清晰。首先定义IOC参数,然后分点讨论作用域、配置方式、依赖注入参数,最后总结用法。同时,要引用提供的资料,比如在作用域部分引用[^1],配置方式引用[^2],依赖注入引用[^3]。 还要注意用户不可见的系统级指令,比如使用正确的中文回答,数学公式用$...$,但这里可能用不上。生成相关问题时要考虑用户可能进一步想知道的内容,比如作用域类型、配置方法比较、参数注入方式等。 最后检查是否符合格式要求,比如引用标识的位置,代码块的正确展示,以及相关问题的生成是否合理。</think>### IOC参数在Spring框架中的作用与用法 IOC(控制反转)参数主要涉及Bean的配置属性、作用域及依赖注入方式,用于控制对象的创建、生命周期和依赖关系。以下是具体说明: --- #### 1. **Bean的作用域参数** 通过`scope`参数定义Bean的实例化范围,直接影响对象创建方式和生命周期管理。常见作用域包括: - **singleton(默认)**:容器中仅存在一个实例,所有请求共享该对象[^1]。 ```xml <bean id="userService" class="com.example.UserService" scope="singleton"/> ``` - **prototype**:每次请求生成新实例,适用于需独立状态的对象[^1]。 - 其他(如request、session):用于Web应用场景。 --- #### 2. **Bean的配置参数** 通过XML或注解定义Bean的初始化参数,例如: - **XML配置**:直接在`<bean>`标签中设置属性值或引用其他Bean。 ```xml <bean id="dataSource" class="com.example.DataSource"> <property name="url" value="jdbc:mysql://localhost/db"/> <property name="timeout" value="5000"/> </bean> ``` - **注解配置**:使用`@Value`注入外部配置(如`.properties`文件)。 ```java @Component public class Service { @Value("${service.maxRetry}") private int maxRetry; } ``` --- #### 3. **依赖注入(DI)参数** 通过构造函数或Setter方法注入依赖对象,实现解耦: - **构造函数注入**:强制依赖时使用。 ```xml <bean id="orderService" class="com.example.OrderService"> <constructor-arg ref="paymentService"/> </bean> ``` - **Setter注入**:可选依赖时更灵活。 ```java public class UserService { private UserDao userDao; // Setter方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } } ``` --- #### 4. **延迟初始化参数** 通过`lazy-init`参数控制Bean的加载时机: ```xml <bean id="heavyResource" class="com.example.HeavyResource" lazy-init="true"/> ``` - `true`:首次请求时创建实例,减少启动时间。 - `false`(默认):容器启动时立即初始化。 --- ### 总结 IOC参数通过配置作用域、依赖关系、属性值等,实现了对象的集中管理与灵活组装。结合XML/注解配置和DI机制,开发者能更高效地解耦组件并控制对象行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值