Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

Spring进阶之路(1)-Spring核心机制:依赖注入/控制反转

原文地址:http://blog.csdn.net/wangyang1354/article/details/50757098


我们经常会遇到这样一种情景,就是在我们开发项目的时候经常会在一个类中调用其他的类中的方法,来完成我们期望的任务,大部分的情况下往往会采用在当前需要的这个类里面new一个实例出来,然后调用他的方法,那么这样的话会有个问题,就是有一天我想改变下这个类,改为其他的名称,那么这时候必须要做的是同时去调用方的类文件中改变这个改变的类的名称。这样的情况是因为代码的耦合带来了后期维护成本的增加,那么spring的出现就可以很好的起到解耦的作用,而他的核心机制就是依赖注入。

依赖注入与控制反转


依赖注入:对于spring而言,将自己置身于spring的立场上去看,当调用方需要某一个类的时候我就为你提供这个类的实例,就是说spring负责将被依赖的这个对象赋值给调用方,那么就相当于我为调用方注入了这样的一个实例。从这方面来看是依赖注入。


控制反转:对于调用方来说,通常情况下是我主动的去创建的,也就是对于这个对象而言我是控制方,我有他产生与否的权力,但是,现在变了,现在变为spring来创建对象的实例,而我被动的接受,从这一点上看,是控制反转。


这两者的意思是一致的,就看你从谁的角度去看这个问题。不同的角度那么看到的问题可能是不一样的。



依赖注入两种方式


1.设值注入


设值注入:通过set的方式注入值.Ioc容器通过成员变量的setter方法来注入被依赖的对象,这种注入方式简单,直观,因而在spring中大量的使用。

下面我们采用实际的例子来体会一下:

假设这样的一个场景,我想打印消息,这样一件事情

首先定义一个MessageService的接口。

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. public interface MessageService {  
  4.   
  5.     /** 
  6.      * 消息打印 
  7.      */  
  8.     public void printMessage();  
  9. }  



然后实现这个接口,并实现这个方法。

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. public class MessagePrinter implements MessageService {  
  4.   
  5.     @Override  
  6.     public void printMessage() {  
  7.         System.out.println(“输出消息!”);  
  8.     }  
  9.   
  10. }  



那么对于我而言,我也定义一个person的接口

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. public interface Person {  
  4.   
  5.     /** 
  6.      * 人发送消息 
  7.      */  
  8.     public void sendMessage();  
  9. }  

我来实现人这个接口

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. public class WangYang implements Person{  
  4.   
  5.     private MessageService service;  
  6.       
  7.     public void setService(MessageService service) {  
  8.         this.service = service;  
  9.     }  
  10.   
  11.     @Override  
  12.     public void sendMessage() {  
  13.         this.service.printMessage();  
  14.     }  
  15.   
  16. }  

Spring的配置文件:

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. <?xml version=“1.0” encoding=“UTF-8”?>  
  2. <beans xmlns=“http://www.springframework.org/schema/beans”  
  3.        xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”  
  4.        xsi:schemaLocation=”  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>  
  6.   
  7. <!– bean definitions here –>  
  8.     <bean id = “messageService” class = “com.siti.spring20160227.MessagePrinter”></bean>  
  9.     <bean id = “wy” class = “com.siti.spring20160227.WangYang”>  
  10.         <property name=“service” ref=“messageService”></property>  
  11.     </bean>  
  12. </beans>  



测试类如下:

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class MainTest {  
  7.   
  8.     public static void main(String[] args) {  
  9.         ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);  
  10.         Person person = context.getBean(“wy”, Person.class);  
  11.         person.sendMessage();  
  12.     }  
  13. }  


2.构造注入


通过构造函数的方式注入。spring以反射的方式执行带指定参数的构造器,当执行带参数的构造器时就可以通过构造器的参数赋值给成员变量,完成构造注入。


那么现在需求变了,我需要改一些东西,下面可以注意下我主要改动了哪里:

在WangYang这个类中添加有参数和无参数的构造函数:

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. package com.siti.spring20160227;  
  2.   
  3. public class WangYang implements Person{  
  4.   
  5.     private MessageService service;  
  6.       
  7.     <span style=“color:#33ff33;”>public WangYang() {  
  8.         super();  
  9.     }  
  10.       
  11.     public WangYang(MessageService service) {  
  12.         this.service = service;  
  13.     }  
  14.   
  15.     </span>public void setService(MessageService service) {  
  16.         this.service = service;  
  17.     }  
  18.   
  19.     @Override  
  20.     public void sendMessage() {  
  21.         this.service.printMessage();  
  22.     }  
  23.   
  24. }  



在Spring配置文件中,稍微改动,即将原来的设值注入换为构造注入即可。

[java] 
view plain
 copy

 
在CODE上查看代码片
派生到我的代码片

  1. <?xml version=“1.0” encoding=“UTF-8”?>  
  2. <beans xmlns=“http://www.springframework.org/schema/beans”  
  3.        xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”  
  4.        xsi:schemaLocation=”  
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>  
  6.   
  7. <!– bean definitions here –>  
  8.     <bean id = “messageService” class = “com.siti.spring20160227.MessagePrinter”></bean>  
  9.     <bean id = “wy” class = “com.siti.spring20160227.WangYang”>  
  10.         <!– <property name=“service” ref=“messageService”></property> –>  
  11.         <span style=“color:#33ff33;”><constructor-arg ref=“messageService”></constructor-arg></span>  
  12.     </bean>  
  13. </beans>  


这样再次运行MainTest类,程序正常运行。所以从这里也可以体会到,spring这种解耦的方便性和重要性。



设值注入和构造注入的对比


这两种方式,效果是一样的,注入的时机不同,设值注入是先调用无参的构造函数,创建出实例后然后调用set方法注入属性值。而构造输入是通过在调用构造函数初始化实例的同时完成了注入。


设值注入的优点


1. 通过set的方式设定依赖关系显得更加直观,自然,和javabean写法类似。

2. 复杂的依赖关系,采用构造注入会造成构造器过于臃肿,spring 实例化的时候同时实例化其依赖的全部实例,导致性能下降,set方式可以避免这些问题。

3. 在成员变量可选的情况下,构造注入不够灵活。


构造注入的优点


某些特定的情况下,构造注入比设值注入好一些。

1. 构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入,构造注入可以清楚的分清注入的顺序。

2. 组件的调用者无需知道组件内部的依赖关系,符合高内聚原则。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/109124.html原文链接:https://javaforall.net

(0)
上一篇 2021年9月13日 上午6:00
下一篇 2021年9月13日 上午7:00


相关推荐

  • (详细图解)VS2017安装教程

    (详细图解)VS2017安装教程VS2017版本同15版一样,细分为三个版本,分别是:社区版(Community):免费提供给单个开发人员,给予初学者及大部分程序员支持,可以无任何经济负担、合法地使用。 企业版:为正规企业量身定做,能够提供点对点的解决方案,充分满足企业的需求。企业版官方售价2999美元/年或者250美元/月。 专业版:适用于专业用户或者小团体。虽没有企业版全面的功能,但相比于免费的社区版,…

    2022年4月28日
    61
  • crontab 详解

    crontab 详解cron 是一个可以用来根据时间 日期 月份 星期的组合来调度对重复任务的执行的守护进程 cron 假定系统持续运行 如果当某任务被调度时系统不在运行 该任务就不会被执行 要使用 cron 服务 你必须安装了 nbsp vixie cron nbsp RPM 软件包 而且必须在运行 crond nbsp 服务 要判定该软件包是否已安装 使用 nbsp rpm qvixie cron nbsp 命令 要判定该服务是否在运行 使

    2026年3月17日
    1
  • 重磅升级| Copilot Studio 一站式智能体平台,助力企业智能体化转型

    重磅升级| Copilot Studio 一站式智能体平台,助力企业智能体化转型

    2026年3月16日
    2
  • vue路由守卫

    vue路由守卫路由守卫分为三种 分别是 全局路由守卫 组件路由守卫 独享路由守卫 一 全局守卫全局守卫又分为全局前置守卫 和后置守卫 1 router beforeEach to from next gt 回调函数中的参数 to 进入到哪个路由去 from 从哪个路由离开 next 函数 决定是否展示你要看到的路由页面 从名字全局前置守卫不难理解 它是全局的 即对整个单页应用 SPA 中的所有路由都生效 所以当定义了全局的前置守卫 在进入每一个路由之

    2026年3月20日
    2
  • 阿里云通义千问 Qwen3-Coder 宣布开源:480B 参数、原生支持 256K 上下文,可与 Claude Sonnet4 媲美

    阿里云通义千问 Qwen3-Coder 宣布开源:480B 参数、原生支持 256K 上下文,可与 Claude Sonnet4 媲美

    2026年3月13日
    2
  • Windows系统重装Linux系统

    Windows系统重装Linux系统PC机以前是Windows系统现在重装Linux系统材料:8G以上U盘(eveything版本很大,如果U盘容量不足请选择DVD版本ISO)UltralSOLinux系统(Centos7_64_eveything.iso)tips:准…

    2022年6月28日
    56

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号