IoC容器和 Dependency Injection模式

这是一个叫 Bromon blog 上 找到的浅显易懂的答案。下面就是引用他说的话:


 

IoC DI

   首先想说说 IoC Inversion of Control ,控制倒转)。这是 spring 的核心,贯穿始终。所谓 IoC ,对于 spring 框架来说,就是由 spring 来负责控制对象的生命周期和 对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的? 常见的情况是,我们到处去看哪里有长得漂亮身材又好的 mm ,然后打 听她们的兴趣爱 好、 qq 号、电话号、 ip 号、 iq ……… ,想办法认识她们,投其所好送其所要,然后嘿嘿 …… 这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传 统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己 new 一个,或者从 JNDI 中查询一个),使用完之后还要将对象销毁(比 Connection 等),对象始终会和其他的接口或类藕合起来。

  那么 IoC 是如何做的呢?有点像通过婚介找女朋 友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚 介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速 度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我 们的要求,提供一个 mm ,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出 异常。整个过程不再由我自己控 制,而是有婚介这样一个类似容器的机构 来控制。 Spring 所倡导的开发方式就是如此,所有 的类都会在 spring 容器中登记,告诉 spring 你是个什 么东西,你 需要什么东西,然后 spring 会在系统运行到适当的时候,把你 要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 spring 。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象 都被 spring 控 制,所以这叫控制反转。如果你还不明白的话,我决定放弃。

IoC 的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过 DI Dependency Injection ,依赖注入)来实现的。比如对象 A 需要操作数据库,以前我们总是要在 A 中自己编写代码来获得一个 Connection 对象,有了 spring 我们就只需要告诉 spring A 中需要一 个 Connection ,至于这个 Connection 怎么构造,何时构造, A 不需要知道。在系统 运行时, spring 会在适当的时候制造一个 Connection ,然后像打针一样,注射到 A 当中,这样就完成了对各个对象之间关系的控制。 A 需要依赖 Connection 才能正常运行,而这个 Connection 是由 spring 注 入到 A 中的,依赖注入的名字就这么来的。那么 DI 是如何实现的呢? Java 1.3 之后一个重要特征是反射( reflection ),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性, spring 就是通过反射来实现注入的。关于反射的相关资料请查阅 java doc


    我想通过 Bromon 的介绍,大家对 IoC DI 都有了比 较生动的理解了。再来看看《 expert one-on-one J2EE Development without EJB 中文版》是怎么解释这两 个概念的。书上是这么说的:

IoC 是一个很大的概念,可以用不同的方式来实现。主要的实现形式有两种 :

依赖查找:容器提供回调接口和上下文环境给组件。 EJB Apache Avalon 都是使用这种方式。

依赖注入:组件不做定位查询,只是提供普通的 Java 方法让容器去决定依赖关系。容器全权负责组件的装配,它会把符合依赖关系的对象通过 JavaBean 属性或者构造子传递给需要的对象。通过 JavaBean 属性注射依赖关系的做法称为设值方法注入( Setter Injection );将依赖关系作为构造子参数传入的做法称为构造子注 入( Constructor Injection )。

附图说明:

 

spring_2.jpg

   

到这里,大家应该对 IoC DI 都有了初 步的认识了。其实就 Spring 来说,就是 JavaBean Spring 来 管理组装,表面上看就少了几个 new 字,其 实就是为了降低耦合度,这也是我们做软件的目标之一。

至于 Spring 是 怎样实现 IoC 的, expert one-on-one J2EE Development without EJB 中文版》第七章“ Spring 框 架介绍”很详细的列举了多种方法。说实在,一下子看这么多,我真有点糊涂了。我还是自己写个 Demo 熟悉一下大名鼎鼎的 Spring 吧。

首先得下载 Spring Spring 网 上有两种 Spring 包一种是 spring-framework-1.2.6-with-dependencies.zip ,另一种是 spring-framework-1.2.6.zip 。当然最好是下载 spring-framework-1.2.6-with-dependencies.zip 形式的,因为里面包括了更多的东东。 spring-framework-1.2.6-with-dependencies.zip 的下载地址是: http://prdownloads.sourceforge.net/springframework/spring-framework-1.2.6-with-dependencies.zip

下载下来,解压后,你会发现里面有很多 jar 文件。因为刚刚接触 Spring ,因此我只需要 spring-core.jar spring-framework-1.2.6/dist ), 将其导入 eclipse 的构建路径中。另外, log 日志是需要的,这也是为了养成良好的编程习惯。将 log4j-1.2.9.jar spring-framework-1.2.6/lib/log4j )和 commons-logging.jar spring-framework-1.2.6/lib/jakarta-commons )导入到构建路径中。

准备就绪,开始写 Demo 了。

我的工程的结构是:

   spring_1.jpg

1、 log4j.properties 代码:

log4j.rootLogger = Debug, stdout
log4j.appender.stdout
= org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout
= org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern
=% c{ 1 -   % m % n

 

如何使用 Log4j ,请看我的另一篇转贴的文章: 如何使用 Log4J

 

2、 HelloBean 的代码:

package  com;

public   class  HelloBean {
    
private  String helloworld = " Hello!World! " ;
    
    
public  String getHelloworld() {
        
return  helloworld;
    }
    
    
public   void  setHelloworld(String helloworld) {
        
this .helloworld  =  helloworld;
    }
}


 

这是一个简单的 JavaBean ,有个 String 类型的 helloworld 属性,初始值是 "Hello!World!"  

3、 Bean.xml 代码:

<? xml version = " 1.0 "  encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC  " -//SPRING/DTD BEAN/EN "  
    
" http://www.springframework.org/dtd/spring-beans.dtd " >

< beans >
   
< bean id = " helloBean "   class = " com.HelloBean " >
        
< property name = " helloworld " >
            
< value > Hello ! Rick </ value >
        
</ property >
   
</ bean >
</ beans >

 

        Spirng重点之一就是配置文件,上面是个相当简单的配置文件,我想大家都应该看得懂。最后就是写应用程序了。

4、 Test 的代码:

 

package  com;

import  org.springframework.beans.factory. * ;
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) {
        
// 实例化JavaBean,主要是为了比较new对象和依赖注入两者的区别
        HelloBean hellobean = new  HelloBean();
        System.out.println(hellobean.getHelloworld());
        
        
// 通过Spring访问JavaBean组件
        Resource resource = new  ClassPathResource( " com/bean.xml " );
        BeanFactory factory
= new  XmlBeanFactory(resource);
        hellobean
= (HelloBean)factory.getBean( " helloBean " );
        System.out.println(hellobean.getHelloworld());
    }
}

    这个Demo很好的阐述了Spring的Ioc,其实就Spring而言,就是通过配置文件,让Spring如同一个管家一样来管理所有的Bean类。

    Spring的依赖注入相对复杂一点,主要是明白调用别的Bean,不是通过实例化对象来调用,而是告诉Spring,我需要什么Bean,然后 Spring再向你的Bean里面注入你所需要的Bean对象。
    接下来说说代码实现,我只是在刚刚的例子上再添加一点东东。
    首先要增加一个HelloImp的接口,这是问什么呢,那你得问Spring,它定的规矩:JavaBean的实现要有两个部分,一个接口,一个默认实 现。你不照做就不行。
    HelloImp代码:

     
package  com;

public   interface  HelloImp {
    
public   void  getName();
}

   
    实现HelloImp的Hello代码:

  
package  com;

public   class  Hello  implements  HelloImp {
    
public   void  getName(){
        System.out.println(
" Jack " );
    }
}

         
    接着就是在 HelloBean 中调用 Hello 了。 Spring 的不同之处也在这体现出来。

package  com;

public   class  HelloBean {
    
private  String helloworld = " Hello!World! " ;
    
private  HelloImp hello;    // 注意这个私有对象是 借口

    
public  String getHelloworld() {
        
return  helloworld;
    }
    
    
public   void  setHelloworld(String helloworld) {
        
this .helloworld  =  helloworld;
    }
    
    
public   void  setHello(HelloImp hello) {
        
this .hello  =  hello;
    }
    
  
public   void  get(){
        
this
.hello.getName();
   }

}

    注意字体加粗的地方。

    配置文件也需要增加一点东西:

   
<? xml version = " 1.0 "  encoding = " GBK " ?>
<! DOCTYPE beans PUBLIC  " -//SPRING/DTD BEAN/EN "  
    
" http://www.springframework.org/dtd/spring-beans.dtd " >

< beans >
<! —注意引用的类是具体的类Hello -->
   
< bean id = " myHello "   class = " com.Hello " >
   
</ bean >
   
< bean id = " helloBean "   class = " com.HelloBean " >
        
< property name = " helloworld " >
            
< value > Hello ! Rick </ value >
        
</ property >
       
< property name = " hello " >
           
< ref bean = " myHello " ></ ref >
       
</ property >

   
</ bean >
</ beans >


    注意字体加粗的部分。

    最后在 Test 中添加 一句 hellobean.get(); 就可以看到结果了。

package  com;

import  org.springframework.beans.factory. * ;
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) {
        HelloBean hellobean
= new  HelloBean();
        System.out.println(hellobean.getHelloworld());
        
        Resource resource
= new  ClassPathResource( " com/bean.xml " );
        BeanFactory factory
= new  XmlBeanFactory(resource);
        
        hellobean
= (HelloBean)factory.getBean( " helloBean " );
        System.out.println(hellobean.getHelloworld());
        hellobean.get();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值