理解依赖注入(IOC)和学习Unity

IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection)。
作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口。当系统重构的时候,代码的改写量将大大减少。
理解依赖注入:
    当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例。然而采用依赖注入的方式,创建被调用者的工作不再由调用者来完成,因此叫控制反转,创建被调用者的实例的工作由IOC容器来完成,然后注入调用者,因此也称为依赖注入。
举个有意思的例子(来源于互联网)

假如我们要设计一个Girl和一个Boy类,其中Girl有Kiss方法,即Girl想要Kiss一个Boy,首先问题是Girl如何认识Boy?
    在我们中国常见的MM认识GG的方式有以下几种:
    A 青梅竹马    B 亲友介绍   C 父母包办
    哪一种是最好的?
1.青梅竹马:很久很久以前,有个有钱的地主家的一闺女叫Lily,她老爸把她许配给县太爷的儿子Jimmy,属于指腹为婚,Lily非常喜欢kiss,但是只能kiss Jimmy

public class Lily{
        public Jimmy jimmy;
        public Girl()
        {
            jimmy=new Jimmy();
        }
        public void Kiss()
        {
            jimmy.Kiss();
        }
    }  

    public class Jimmy
    {
        public void Kiss()
        {
            Console.WriteLine("kissing");
        }
    }
这样导致Lily对Jimmy的依赖性非常强,紧耦合。

2.亲友介绍:经常Kiss同一个人令Lily有些厌恶了,她想尝试新人,于是与Jimmy分手了,通过亲朋好友(中间人)来介绍

public class Lily{
        public Boy boy;   

        public Girl()
        {
            boy=BoyFactory.createBoy();
        }
        public void Kiss()
        {
            boy.Kiss();
        }
    }  

亲友介绍,固然是好。如果不满意,尽管另外换一个好了。但是,亲友BoyFactory经常是以Singleton的形式出现,不然就是,存在于Globals,无处不在,无处不能。实在是太繁琐了一点,不够灵活。我为什么一定要这个亲友掺和进来呢?为什么一定要付给她介绍费呢?万一最好的朋友爱上了我的男朋友呢?

3.父母包办:一切交给父母,自己不用非吹灰之力,Lily在家只Kiss

public class Lily{
        public Boy boy;
        public Girl(Boy boy)
        {
            this.boy=boy;
        }
        public void Kiss()
        {
            this.boy.Kiss();
        }
    }  

Well,这是对Girl最好的方法,只要想办法贿赂了Girl的父母,并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。这就是IOC,将对象的创建和获取提取到外部。由外部容器提供需要的组件。

在设计模式中我们应该还知道依赖倒转原则,应是面向接口编程而不是面向功能实现,好处是:多实现可以任意切换,我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话,还可以kiss可爱的kitten和慈祥的grandmother

好在.net中微软有一个轻量级的IoC框架Unity,支持构造器注入,属性注入,方法注入如下图所示

具体使用方法如下图所示

using System;  

using Microsoft.Practices.Unity;  

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建容器
            IUnityContainer container=new UnityContainer();
            //注册映射
            container.RegisterType<IKiss, Boy>();
            //得到Boy的实例
            var boy = container.Resolve<IKiss>();  

            Lily lily = new Lily(boy);
            lily.kiss();
        }
    }  

    public interface IKiss
    {
        void kiss();
    }  

    public class Lily:IKiss
    {  

        public IKiss boy;   

        public Lily(IKiss boy)
        {
            this.boy=boy;
        }
        public void kiss()
        {
            boy.kiss();
            Console.WriteLine("lily kissing");
        }
    }  

    public class Boy : IKiss
    {
        public void kiss()
        {
            Console.WriteLine("boy kissing");
        }
    }
}
如果采用配置文件注册的话

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <containers>
      <container name="defaultContainer">
        <register type="命名空间.接口类型1,命名空间" mapTo="命名空间.实现类型1,命名空间" />
        <register type="命名空间.接口类型2,命名空间" mapTo="命名空间.实现类型2,命名空间" />
      </container>
    </containers>
  </unity>
</configuration>  

配置的后台代码:

UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)
            as UnityConfigurationSection;
configuration.Configure(container, "defaultContainer");
可以通过方法ResolveAll来得到所有注册对象的实例:
var Instances = container.Resolve<IKiss>();

Martin Fowler在那篇著名的文章《Inversion of Control Containers and the Dependency Injection pattern》中将具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:

类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;
构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。

我们创建一个控制台程序,定义如下几个接口(IA、IB、IC和ID)和它们各自的实现类(A、B、C、D)。在类型A中定义了3个属性B、C和D,其类型分别为接口IB、IC和ID。其中属性B在构在函数中被初始化,以为着它会以构造器注入的方式被初始化;属性C上应用了DependencyAttribute特性,意味着这是一个需要以属性注入方式被初始化的依赖属性;属性D则通过方法Initialize初始化,该方法上应用了特性InjectionMethodAttribute,意味着这是一个注入方法在A对象被IoC容器创建的时候会被自动调用。

public interface IA { }
    public interface IB { }
    public interface IC { }
    public interface ID { }  

    public class A : IA
    {
        public IB B { get; set; }
        [Dependency]
        public IC C { get; set; }
        public ID D { get; set; }  

        public A(IB b)
        {
            this.B = b;
        }
        [InjectionMethod]
        public void Initalize(ID d)
        {
            this.D = d;
        }
    }
    public class B : IB { }
    public class C : IC { }
    public class D : ID { }  

然后我们为该应用添加一个配置文件,并定义如下一段关于Unity的配置。这段配置定义了一个名称为defaultContainer的Unity容器,并在其中完成了上面定义的接口和对应实现类之间映射的类型匹配。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <containers>
      <container name="defaultContainer">
        <register type="UnityDemo.IA,UnityDemo" mapTo="UnityDemo.A, UnityDemo"/>
        <register type="UnityDemo.IB,UnityDemo" mapTo="UnityDemo.B, UnityDemo"/>
        <register type="UnityDemo.IC,UnityDemo" mapTo="UnityDemo.C, UnityDemo"/>
        <register type="UnityDemo.ID,UnityDemo" mapTo="UnityDemo.D, UnityDemo"/>
      </container>
    </containers>
  </unity>
</configuration>  

最后在Main方法中创建一个代表IoC容器的UnityContainer对象,并加载配置信息对其进行初始化。然后调用它的泛型的Resolve方法创建一个实现了泛型接口IA的对象。最后将返回对象转变成类型A,并检验其B、C和D属性是否是空

class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
            configuration.Configure(container, "defaultContainer");
            A a = container.Resolve<IA>() as A;
            if (null!=a)
            {
                Console.WriteLine("a.B==null?{0}",a.B==null?"Yes":"No");
                Console.WriteLine("a.C==null?{0}", a.C == null ? "Yes" : "No");
                Console.WriteLine("a.D==null?{0}", a.D == null ? "Yes" : "No");
            }
        }
    }  

从如下给出的执行结果我们可以得到这样的结论:通过Resolve<IA>方法返回的是一个类型为A的对象,该对象的三个属性被进行了有效的初始化。这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性B)、属性注入(属性C)和方法注入(属性D)

  a.B == null ? No
 a.C == null ? No
 a.D == null ? No

http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html

IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection)。
作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口。当系统重构的时候,代码的改写量将大大减少。
理解依赖注入:
    当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例。然而采用依赖注入的方式,创建被调用者的工作不再由调用者来完成,因此叫控制反转,创建被调用者的实例的工作由IOC容器来完成,然后注入调用者,因此也称为依赖注入。
举个有意思的例子(来源于互联网)

假如我们要设计一个Girl和一个Boy类,其中Girl有Kiss方法,即Girl想要Kiss一个Boy,首先问题是Girl如何认识Boy?

在我们中国常见的MM认识GG的方式有以下几种:

A 青梅竹马    B 亲友介绍   C 父母包办

哪一种是最好的?

1.青梅竹马:很久很久以前,有个有钱的地主家的一闺女叫Lily,她老爸把她许配给县太爷的儿子Jimmy,属于指腹为婚,Lily非常喜欢kiss,但是只能kiss Jimmy

  1. public class Lily{
  2. public Jimmy jimmy;
  3. public Girl()
  4. {
  5. jimmy=new Jimmy();
  6. }
  7. public void Kiss()
  8. {
  9. jimmy.Kiss();
  10. }
  11. }
  12. public class Jimmy
  13. {
  14. public void Kiss()
  15. {
  16. Console.WriteLine("kissing");
  17. }
  18. }

这样导致Lily对Jimmy的依赖性非常强,紧耦合。

2.亲友介绍:经常Kiss同一个人令Lily有些厌恶了,她想尝试新人,于是与Jimmy分手了,通过亲朋好友(中间人)来介绍

  1. public class Lily{
  2. public Boy boy;
  3. public Girl()
  4. {
  5. boy=BoyFactory.createBoy();
  6. }
  7. public void Kiss()
  8. {
  9. boy.Kiss();
  10. }
  11. }

亲友介绍,固然是好。如果不满意,尽管另外换一个好了。但是,亲友BoyFactory经常是以Singleton的形式出现,不然就是,存在于Globals,无处不在,无处不能。实在是太繁琐了一点,不够灵活。我为什么一定要这个亲友掺和进来呢?为什么一定要付给她介绍费呢?万一最好的朋友爱上了我的男朋友呢?

3.父母包办:一切交给父母,自己不用非吹灰之力,Lily在家只Kiss

  1. public class Lily{
  2. public Boy boy;
  3. public Girl(Boy boy)
  4. {
  5. this.boy=boy;
  6. }
  7. public void Kiss()
  8. {
  9. this.boy.Kiss();
  10. }
  11. }

Well,这是对Girl最好的方法,只要想办法贿赂了Girl的父母,并把Boy交给他。那么我们就可以轻松的和Girl来Kiss了。看来几千年传统的父母之命还真是有用哦。至少Boy和Girl不用自己瞎忙乎了。这就是IOC,将对象的创建和获取提取到外部。由外部容器提供需要的组件。

在设计模式中我们应该还知道依赖倒转原则,应是面向接口编程而不是面向功能实现,好处是:多实现可以任意切换,我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话,还可以kiss可爱的kitten和慈祥的grandmother

好在.net中微软有一个轻量级的IoC框架Unity,支持构造器注入,属性注入,方法注入如下图所示

具体使用方法如下图所示

  1. using System;
  2. using Microsoft.Practices.Unity;
  3. namespace ConsoleApplication9
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. //创建容器
  10. IUnityContainer container=new UnityContainer();
  11. //注册映射
  12. container.RegisterType<IKiss, Boy>();
  13. //得到Boy的实例
  14. var boy = container.Resolve<IKiss>();
  15. Lily lily = new Lily(boy);
  16. lily.kiss();
  17. }
  18. }
  19. public interface IKiss
  20. {
  21. void kiss();
  22. }
  23. public class Lily:IKiss
  24. {
  25. public IKiss boy;
  26. public Lily(IKiss boy)
  27. {
  28. this.boy=boy;
  29. }
  30. public void kiss()
  31. {
  32. boy.kiss();
  33. Console.WriteLine("lily kissing");
  34. }
  35. }
  36. public class Boy : IKiss
  37. {
  38. public void kiss()
  39. {
  40. Console.WriteLine("boy kissing");
  41. }
  42. }
  43. }

如果采用配置文件注册的话

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <configSections>
  4. <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  5. </configSections>
  6. <unity>
  7. <containers>
  8. <container name="defaultContainer">
  9. <register type="命名空间.接口类型1,命名空间" mapTo="命名空间.实现类型1,命名空间" />
  10. <register type="命名空间.接口类型2,命名空间" mapTo="命名空间.实现类型2,命名空间" />
  11. </container>
  12. </containers>
  13. </unity>
  14. </configuration>

配置的后台代码:

  1. UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)
  2. as UnityConfigurationSection;
  3. configuration.Configure(container, "defaultContainer");

可以通过方法ResolveAll来得到所有注册对象的实例:
var Instances = container.Resolve<IKiss>();

Martin Fowler在那篇著名的文章《Inversion of Control Containers and the Dependency Injection pattern》中将具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:

  • 类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;
  • 构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;
  • 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
  • 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。

我们创建一个控制台程序,定义如下几个接口(IA、IB、IC和ID)和它们各自的实现类(A、B、C、D)。在类型A中定义了3个属性B、C和D,其类型分别为接口IB、IC和ID。其中属性B在构在函数中被初始化,以为着它会以构造器注入的方式被初始化;属性C上应用了DependencyAttribute特性,意味着这是一个需要以属性注入方式被初始化的依赖属性;属性D则通过方法Initialize初始化,该方法上应用了特性InjectionMethodAttribute,意味着这是一个注入方法在A对象被IoC容器创建的时候会被自动调用。

  1. public interface IA { }
  2. public interface IB { }
  3. public interface IC { }
  4. public interface ID { }
  5. public class A : IA
  6. {
  7. public IB B { get; set; }
  8. [Dependency]
  9. public IC C { get; set; }
  10. public ID D { get; set; }
  11. public A(IB b)
  12. {
  13. this.B = b;
  14. }
  15. [InjectionMethod]
  16. public void Initalize(ID d)
  17. {
  18. this.D = d;
  19. }
  20. }
  21. public class B : IB { }
  22. public class C : IC { }
  23. public class D : ID { }

然后我们为该应用添加一个配置文件,并定义如下一段关于Unity的配置。这段配置定义了一个名称为defaultContainer的Unity容器,并在其中完成了上面定义的接口和对应实现类之间映射的类型匹配。

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <configSections>
  4. <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  5. </configSections>
  6. <unity>
  7. <containers>
  8. <container name="defaultContainer">
  9. <register type="UnityDemo.IA,UnityDemo" mapTo="UnityDemo.A, UnityDemo"/>
  10. <register type="UnityDemo.IB,UnityDemo" mapTo="UnityDemo.B, UnityDemo"/>
  11. <register type="UnityDemo.IC,UnityDemo" mapTo="UnityDemo.C, UnityDemo"/>
  12. <register type="UnityDemo.ID,UnityDemo" mapTo="UnityDemo.D, UnityDemo"/>
  13. </container>
  14. </containers>
  15. </unity>
  16. </configuration>

最后在Main方法中创建一个代表IoC容器的UnityContainer对象,并加载配置信息对其进行初始化。然后调用它的泛型的Resolve方法创建一个实现了泛型接口IA的对象。最后将返回对象转变成类型A,并检验其B、C和D属性是否是空

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. UnityContainer container = new UnityContainer();
  6. UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
  7. configuration.Configure(container, "defaultContainer");
  8. A a = container.Resolve<IA>() as A;
  9. if (null!=a)
  10. {
  11. Console.WriteLine("a.B==null?{0}",a.B==null?"Yes":"No");
  12. Console.WriteLine("a.C==null?{0}", a.C == null ? "Yes" : "No");
  13. Console.WriteLine("a.D==null?{0}", a.D == null ? "Yes" : "No");
  14. }
  15. }
  16. }

从如下给出的执行结果我们可以得到这样的结论:通过Resolve<IA>方法返回的是一个类型为A的对象,该对象的三个属性被进行了有效的初始化。这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性B)、属性注入(属性C)和方法注入(属性D)

  a.B == null ? No
 a.C == null ? No
 a.D == null ? No
时间: 2024-11-08 05:42:03

理解依赖注入(IOC)和学习Unity的相关文章

【转】理解依赖注入(IOC)和学习Unity

IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection).作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口.当系统重构的时候,代码的改写量将大大减少.理解依赖注入:    当一个类的实例需要另一个类的实例协助时,在传统的程序设计过程中,通常有调用者来创建被调用者的实例.然而采用依赖注入的方式,创建被调用者的工作不再由调用者来完成,因此叫控制反转,创建被调用者的实例的工作由IOC容

从壹开始前后端分离【 .NET Core2.0 Api + Vue 3.0 + AOP + 分布式】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

代码已上传Github,文末有地址 说接上文,上回说到了<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之八 || API项目整体搭建 6.3 异步泛型+依赖注入初探>,后来的标题中,我把仓储两个字给去掉了,因为好像大家对这个模式很有不同的看法,嗯~可能还是我学艺不精,没有说到其中的好处,现在在学DDD领域驱动设计相关资料,有了好的灵感再给大家分享吧. 到目前为止我们的项目已经有了基本的雏形,后端其实已经可以搭建自己的接口列表了,框架已

深度理解依赖注入(Dependence Injection)

前面的话:提到依赖注入,大家都会想到老马那篇经典的文章.其实,本文就是相当于对那篇文章的解读.所以,如果您对原文已经有了非常深刻的理解,完全不需要再看此文:但是,如果您和笔者一样,以前曾经看过,似乎看懂了,但似乎又没抓到什么要领,不妨看看笔者这个解读,也许对您理解原文有一定帮助. 1.依赖在哪里    老马举了一个小例子,是开发一个电影列举器(MovieList),这个电影列举器需要使用一个电影查找器(MovieFinder)提供的服务,伪码如下: 1/**//*服务的接口*/  2public

深度理解依赖注入

1.依赖在哪里   老马举了一个小例子,是开发一个电影列举器(MovieList),这个电影列举器需要使用一个电影查找器(MovieFinder)提供的服务,伪码如下: 1/*服务的接口*/ 2public interface MovieFinder { 3    ArrayList findAll(); 4} 5 6/*服务的消费者*/ 7class MovieLister 8{ 9    public Movie[] moviesDirectedBy(String arg) {10     

大话DI依赖注入+IOC控制反转(二) 之 浅析.Net Core中的DI与IOC

原文:大话DI依赖注入+IOC控制反转(二) 之 浅析.Net Core中的DI与IOC   转发时请注明原创作者及地址,否则追究责任.原创:alunchen 在上一篇文章中,我们聊了很多关于定义的方面,比较孤燥,下面我们结合.Net Core聊一下依赖注入&控制反转. 三种对象生命周期 关于.Net Core中的容器,有三种对象的生命周期,这个从网上搜索也有大堆的资料.为了循序渐进,我们这里介绍一下. Transient 称为短暂,意思是需要使用时就创建一个新的对象.从容易层面讲,当从容器取出

理解依赖注入(Dependency Injection)

理解依赖注入 Yii2.0 使用了依赖注入的思想.正是使用这种模式,使得Yii2异常灵活和强大.千万不要以为这是很玄乎的东西,看完下面的两个例子就懂了. class SessionStorage { function __construct($cookieName = 'PHP_SESS_ID') { session_name($cookieName); session_start(); } function set($key, $value) { $_SESSION[$key] = $valu

Angular2基础03: 理解依赖注入

理解依赖注入injector 依赖注入是重要的程序设计模式. Angular 有自己的依赖注入框架,离开了它,几乎没法构建 Angular 应用.下面我分步来加强我对它的理解: 开门见山,什么是依赖注入:它是一种编程模式,可以让类从外部源中获得它的依赖,而不必亲自创建它们 第一步:为什么要解耦? 第二步:实现解耦

android使用篇(四) 注解依赖注入IOC实现绑定控件

在android使用篇(三) MVC模式中提到一个问题: 1) 视图层(View):一般採用XML文件进行界面的描写叙述,使用的时候能够很方便的引入,可是用xml编写了,又须要在Acitvity声明而且实例化,有点麻烦,考虑是否能做一个类似注解实现匹配,或者写一个类获取xml的各个节点然后自己主动进行封装,当然,这仅仅是个想法,以后再实现. 今天最终把这个想法实现了,使用依赖注入IOC注解实现对activity中控件的实例化. 先普及一下java的反射机制和注解机制的知识: 下面引用大神的两篇文

【Spring】Spring依赖注入IOC的设值注入setter

其实标题中如此高大上的名词,只是一个问题,关于在Spring的applicationContext.xml中的如下语句是什么意思? <property name="aService" ref="aService"/> 这类语句在SSH的配置中会大量存在,因为Spring所谓的核心机制就是Spring依赖注入IOC.下面举一个例子说明这个问题: 先贴上目录结构: 在Eclipse中新建一个Java工程,不是JavaWeb,在这个Java配置好Spring3