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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux下luajit安装

    linux下luajit安装#cd /usr/local/#wget http://luajit.org/download/LuaJIT-2.0.4.tar.gz#tar zxvf LuaJIT-2.0.4.tar.gz编辑src/Makefile,注释DLUAJIT_ENABLE_LUA52COMPAT所在的行#make & make install

    2022年10月7日
    4
  • 网络协议之LLDP

    网络协议之LLDP一、协议简介为什么会出现LLDP?随着网络技术的发展,接入网络的设备的种类越来越多,配置越来越复杂,来自不同设备厂商的设备也往往会增加自己特有的功能,这就导致在一个网络中往往会有很多具有不同特性的、来自不同厂商的设备,为了方便对这样的网络进行管理,就需要使得不同厂商的设备能够在网络中相互发现并交互各自的系统及配置信息。LLDP(LinkLayerDiscoveryProtocol,链路层发…

    2022年5月30日
    144
  • android点击按钮打开相册,打开相机的代码[通俗易懂]

    android点击按钮打开相册,打开相机的代码[通俗易懂]打开相册首先在onclick方法中:Intentintent=newIntent();intent.setType(&amp;amp;quot;image/*&amp;amp;quot;);//开启Pictures画面Type设定为imageintent.setAction(Intent.ACTION_GET_CONTENT);startActivityForResult(intent,REQUEST_CODE_SEL…

    2022年9月22日
    2
  • copy.deepcopy()_python 内存管理

    copy.deepcopy()_python 内存管理参考文章http://iaman.actor/blog/2016/04/17/copy-in-python**首先直接上结论:—–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。—–而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被…

    2022年10月3日
    1
  • SpringCloud原理–FeignClient

    SpringCloud原理–FeignClient本文介绍SpringCloud的FeignClient的原理。Feign服务调用的工作原理可以总结为以下几个步骤首先通过@EnableFeignCleints注解开启FeignCleint。根据Feign的规则实现接口,添加@FeignCleint注解。程序启动后,会扫描所有有@FeignCleint的类,并将这些信息注入到ioc容器中。注入时从FeignClientFactoryBean.class获取FeignClient当接口的方法被调用时,通过jdk的代理,来生

    2025年8月29日
    4
  • requiredargsconstructor_gridview控件的事件有哪些

    requiredargsconstructor_gridview控件的事件有哪些1ItemDataBound:数据绑定的时候(正在进行时)发生。2ItemCommand:用来响应Item模板中的控件的事件。如下代码aspx代码:[html]viewplaincopy<asp:RepeaterID=”Repeater1″runat=”server”DataSourceID=”LinqDataSource1…

    2022年10月12日
    5

发表回复

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

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