Spring Ioc、依赖注入原理

Sping  框架的核心就是IOC控制反转和DI依赖注入,并通过这两方面实现松耦合。


IOC控制反转:其实这个Sping构架核心的概念没有这么复杂,更不想书上描述的那样晦涩。Java 程序员都知道:Java程序的每一个业务逻辑至少要两个以上的对象来协作完成。通常每个对象在使用它合作的对象时,自己均要使用像new object()这样的语法

来完成合作对象的申请工作。这个时候你就会发现对象之间的 耦合度 高了。

 (耦合度:是指对模块之间的关联程度的度量。耦合度的强弱取决于模块接口之      间的复杂性、调用模块之间的方式以及通过界面传送的多少。模块之间的耦合度             是指模块之间的:依赖关系、控制关系、调用关系、数据传递关系。模块之间连             系越多,其耦合性越高,同时表名其独立关系越差。


IOC的思想是:用Spring容器来实现这些相互的依赖的对象的创建、协调工作。

对象只需要关系业务逻辑本身就可以了。从这方面来说,对象如何得到它的协作对象的责任就被反转了(IOC)。

 

IOC与ID

首选先来说说IOCInversion of Control,控制倒转)。这个是Spring框架的核心,贯穿始终。所谓的IOC对于Spring框架来说,就是由Spring框架负责控制对象的生命周期和对象之间的关系。举个例子比如:我们是如何找女朋友的呢?常见的是看见长的漂亮的妹子对她有想法,然后打听妹子们的兴趣爱好想办法搞到:QQ号、电话号、微信号等等。然后想尽办法认识她打好关系,投其所好,送其所要。最后就...........嘿嘿嘿,这个过程必定是复杂的深奥的我们必须自己设计和面对每一个环节。传统的程序开发也是如此,在一个对象中如果要使用另外的对象就必须要得到它(自己new一个,或者是从JNDI中查询一个),然后使用完了还要将对象销毁(比如:connection关闭连接释放资源等),这样对象始终会和其他对象的接口或者类耦合起来。



那么IOC是如何做到的呢?举个例子比如:连接上面个例子,接着说。IOC的做法就有点好像通过婚姻介绍所一样。我像婚介提出一个请求,告诉他我要找什么样子的女朋友,比如说像刘亦菲,身材像柳岩,唱歌像张靓颖等等。然后婚介就会按照我们的要求,提供一个妹子,我们只需要和他约会、交往看双方是否相互有意,简单明了。如果婚介提供的妹子不符合我们的要求,我们就会抛出异常表示不满意。整个过程已经不再又我自己控制了,而是有婚介这样一个类似容器的机构来控制。Spring框架所倡导的开发模式也是如此,所有的类多会在Spring容器中登记告诉Spring你是个什么东西,你需要什么东西。然后Spring会在系统运行到适当的时候,把你要的主动给你,同时也把你交给其他需要你的对象。所有类的创建和销毁多由Spring来控制。就是说控制对象的生命周期的不在是引用它的对象了,而是Spring容器。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象多被Spring控制,所有这就叫控制反转IOC



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



如果你还不理解我在说的简单明了些。

1.使用Ioc,对象是变动的接受依赖类,而不是主动去找。Spring容器在实例化的时候主动将它的依赖类注入给它,也可以这样理解:控制反转将类的主动权转移到接口上,依赖注入通过.xml配置文件在实例化时将其依赖注入。

2.例如:比如a类依赖于b类,那么a类之中就有b类的引用(在说简单点就是拥有b类这么一个属性),也就是说a类要想执行一个完整的功能必须要建立一个前提,在a类中实例化b类的一个属性,拥有b类的一切功能,接下来就是依赖注入了。就像前面说的a类想完成一个完整的功能必须要为自己的b类属性实例化,而在MVC设计模式中,这种现象很常见,为了简化这种实例化的工作,Spring容器就产生了。它可以统一管理这种实例化频繁的操作,就是说这种本来由自己实例化的工作交给了Spring容器去控制,这就是控制反转了。实现的案例代码可以看一下代码。

 

  1. //**定义接口B类
  2. public interface B{  
  3.    void doMethod();  
  4. }  
  5.   
  6. //实现接口B类  
  7. public class BImpl implements B{  
  8.    //以及实现doMethod()方法
  9.    public void doMethod(){......}  
  10. }  
  11. //类A
  12. public class A{  
  13.     B obj;  
  14.     public A(){}  
  15.     public void doSth(){  
  16.        ...  
  17.        obj.doMethod();  
  18.     }  
  19.     public void setObj(B b){  
  20.     this.obj = d;     
  21.    }  
  22. }  
  23. 代码中可以看出:  
  24. (1A类的变量obj可以接受任何B类的实例  
  25. (2BImpl实现类的实例不是通过A类自己new出来,而是通过setter来由外部传给它。  
  26. 此时考虑 A类依赖的实例如何从外部注入,就要通过xml定义,Spring容器再依据xml来实例化。  
  27.   
  28. 创建一个spring-context.xml  
  29. <beans>  
  30.  <bean id="B" class="*****.BImpl"> 实体类名包  
  31.  <bean id ="A"  class="****.A">  
  32.     <proproty name="obj">  
  33.     <ref bean ="B"  
  34.     </property>     
  35.  </bean>  
  36. </beans>  
  37. 这里的配置文件将BImpl实现类和A类加入,并将BImpl作为A类的一个参数。  
  38.  容器加载通过xml来实例化相关的bean。
  39. 通过上面不难发现:  
  40. (1) A类是通过接口B类来接受BImpl实例,所以  
  41. 当我们又有新的 B类的实现是,只需要修改xml文件即可。
  42. 通过上例可以总结得出:
    1.依赖类是通过Spring容器解析xml后来注入的,而不是使用它的类(A)来自己制造,这就是依赖的注入。


    2.A类BImpl的依赖转移到对B接口的依赖,控制权由类转移到了接口,即由"实现"转移到"抽象"中。


    3.通过将对实例的依赖,改为对接口的依赖。是面向接口编程的一个要义。也是程序解耦的一个措施。

### Spring IOC 依赖注入的工作原理 Spring IOC(Inversion of Control,控制反转)中的依赖注入(Dependency Injection, DI),是指通过外部配置的方式将对象间的依赖关系交给容器管理,从而减少代码耦合度并提高灵活性。以下是关于 Spring IOC 依赖注入工作原理的具体解释: #### 容器初始化阶段 当 Spring 应用启动时,`ApplicationContext` 或 `BeanFactory` 负责加载配置文件或注解定义的 Bean,并将其注册到内部的数据结构中。这一过程主要包括以下步骤: - **扫描组件**:如果使用基于 XML 配置,则直接解析 `<bean>` 标签;如果是基于 Java 注解,则通过类路径扫描发现带有特定注解(如 `@Component`, `@Service`, `@Repository` 等)的类[^1]。 - **实例化 Bean**:对于每一个被识别出来的 Bean 类型,框架会为其创建实际的对象实例[^2]。 #### 属性填充与依赖解决 一旦所有的 Bean 实例都被成功构建出来之后,下一步就是设置这些 Beans 的属性值以及满足它们之间可能存在的相互引用需求——即执行所谓的“依赖注入”。具体来说: - 当某个 Bean A 需要另一个 Bean B 作为其成员变量时,在默认情况下,Spring 将自动寻找符合条件的候选者并将之赋给前者对应的字段位置上完成装配操作[^3]; - 如果存在多个匹配项或者没有任何合适的选择,则抛出异常提示开发者修正错误配置情况下的行为模式设定问题[^5]。 #### 自动装配策略 为了更精确地指定如何找到目标 bean 来进行注入,Spring 提供了几种不同的 Autowire 模式可供选择: - byName: 根据参数名称去查找对应名字的服务端口; - constructor: 只允许单参构造函数参与反射调用流程. 另外还有一种特别重要的概念叫做原型作用域(Prototype Scope),它意味着每次求都会得到一个新的实体副本而非共享同一个全局唯一版本. ```java @Service public class MyService { @Autowired private AnotherService anotherService; // 使用@Autowired标注实现DI public void doSomething(){ System.out.println(anotherService); } } ``` 上述例子展示了最基础形式下利用注解驱动的方式来达成自动化程度较高的程序开发体验效果的同时也体现了IOC/DI设计理念所带来的诸多好处比如增强模块独立性降低修改成本等等优点[^4]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值