java基础 IoC介绍及其简单实现
2018-02-26 17:05
891 查看
Inverse of Control控制反转)是Spring容器的内核,AOP和声明式事务等功能都是基于此技术实现。
参照实例理解IoC
参考网址中的刘德华饰演墨者革离的例子,能帮助我们更好的理解IoC的原理,因此此处我们依然使用这个例子进行IoC的学习。代码1:通过演员安排剧本
public class MoAttack { public void cityGateAsk() { //演员直接侵入剧本 LiuDeHua liuDeHua = new LiuDeHua(); liuDeHua.responseAsk("Who are you?"); } }
剧本和演员直接耦合
这里可以看出,演员同剧本耦合度太高,如果演员临时出现什么状况,可能就会对整部电影有影响。因此聪明的编剧,在创作时应围绕剧情和故事,而不是某一个演员,这样在能在投入拍摄的时候自由遴选演员,而非只能绑定在刘德华的身上。因此此处我们应该真对角色革离设定一个接口。
代码2:引入革离角色
public class MoAttack { public void cityGateAsk() { //引入革离角色接口IGeLi IGeLi iGeLi = new LiuDeHua(); //调用角色行为 iGeLi.responseAsk("Who are you?"); } }在此处引用了革离角色接口,剧情以角色展开,在拍摄时选择刘德华进行拍摄,进行的也是角色行为。此时墨攻、革离、刘德华的关系就如下图
引入革离角色接口后的关系
此时MoAttach同时依赖于IGeLi接口和LiuDeHua类,并没有达到真正的剧本只依赖于角色的目的。但是实际剧本拍摄中,又离不开演员,因此如何能让LiuDeHua与剧本MoAttach无关,而又能完成角色IGeLi的具体动作呢?当然是具体拍摄时,导演分配LiuDeHua饰演IGeLi角色,导演将MoAttach剧本、IGeLi角色、饰演者联系在一起。
引入导演后,剧本同饰演者解耦通过引入导演,实现了剧本同具体表演者解耦。对应到软件设计中,导演就是一个装配器,安排演员表演具体的角色。
据此我们可以反过来讲解IoC的概念了。IoC字面意思为控制反转,包括两个内容:控制、反转。上述的例子中,控制指的是角色革离扮演者的控制权,而反转是将控制权从剧本中移除,转交到导演的手里。将某一接口具体实现类的控制权从调用类中移除,转交给第三方决定。在Spring中,Spring框架就是第三方。
IoC的类型
从注入方法上划分,可以主要分为三种类型:构造函数注入、属性注入、接口注入。Spring支持构造函数注入和属性输入。下面我们继续以上面的例子来讲述三种实现方法的区别。构造函数注入
在构造函数注入中,通过调用类的构造函数,将接口的具体实现类通过构造函数变量传入。如下述代码所示代码3.1 通过构造函数注入革离实际扮演者
public class MoAttack { private IGeLi geLi; //通过构造函数注入革离的实际扮演者 public MoAttack(IGeLi iGeLi){ this.geLi = iGeLi; } public void cityGateAsk() { this.geLi.responseAsk("Who are you?"); } }此处的MoAttack不关心革离的具体扮演者是谁,只需要这个扮演者按照剧本表演革离的动作即可。而革离的具体表演者由导演来安排。
代码3.2 导演通过剧本的构造函数注入实际表演者
public class Director { private String userName = "FengXiaoGang"; public void directMovie() { //声明革离的实际扮演者 IGeLi geLi = new LiuDeHua(); //通过MoAttack的构造函数注入革离的实际扮演者 MoAttack moAttack = new MoAttack(geLi); moAttack.cityGateAsk(); } }
属性注入
在剧本中,革离虽然是第一主角,但是并非在每个场景都会出现。使用构造函数注入的隔离角色,会在每个场景都出现,这也是不恰当的。这时就可以考虑使用属性注入,属性注入可以通过对象的setter方法,灵活的在需要的时候进行调用类所需依赖的注入。代码3.3 通过setter方法注入实际扮演者
public class MoAttack { private IGeLi geLi; //MoAttack类提供setter方法,用于在导演在需要的时候注入革离的实际扮演者 public void setGeLi(IGeLi geLi) { this.geLi = geLi; } public void cityGateAsk() { this.geLi.responseAsk("Who are you?"); } }
代码3.4 导演注入革离实际扮演者
public class Director { private String userName = "FengXiaoGang"; public void directMovie() { //声明革离实际扮演者 IGeLi geLi = new LiuDeHua(); MoAttack moAttack = new MoAttack(); //调用setter方法注入革离实际扮演者 moAttack.setGeLi(geLi); moAttack.cityGateAsk(); } }在剧本开始,没有革离出场的时候,不生成革离的实际扮演者,等到需要的时候,使用setter方法注入革离的实际扮演者,即可使用。由此可以在需要其他角色出场时,提供其他角色的setter方法,导演在出场时调用setter方法注入实际扮演者即可。
接口注入
将调用类中需要注入的方法提取到接口中,调用类通过实现接口提供的注入方法。为了实现接口注入的形式,应当先生成一个接口方法:代码3.5 声明接口方法
public interface IActorArrange { //声明革离角色的注入方法 void injectGeLi(IGeLi geLi); }
代码3.6 实现接口内的注入方法
public class MoAttack implements IActorArrange { private IGeLi geLi; public void injectGeLi(IGeLi geLi) { this.geLi = geLi; } public void cityGateAsk() { this.geLi.responseAsk("Who are you?"); } }
代码3.7 导演调用接口方法注入革离实际扮演者
public class Director { private String userName = "FengXiaoGang"; public void directMovie() { IGeLi geLi = new LiuDeHua(); MoAttack moAttack = new MoAttack(); moAttack.injectGeLi(geLi); moAttack.cityGateAsk(); } }通过接口注入方法需要额外声明一个接口,增加类的树木,且其实现效果与属性注入没有本质上的区别,因此不提倡采用此方法。
通过容器完成依赖关系的注入
上述代码最终虽然将剧本和实际扮演者解耦,剧本类无需关注角色扮演类的实例化工作,但是这些代码依然存在,只是转移到了导演类中实例化而已。如果制片人想要在改变这一现状,将角色扮演者的筛选工作交给第三方,这样就真正实现了导演、剧本、角色、实际扮演者的真正解耦。所谓第三方在程序中就是一个第三方的容器,它帮助完成类的初始化和实例工作,让开发者从这些底层实现类的实例化、依赖关系装配等工作中脱离出来,专注于更有意义的业务逻辑开发工作。Spring提供的就是这样的容器,它通过配置文件或注解描述类和类的依赖关系,自动完成类的初始化和实例工作。
代码 配置文件片段
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="geli" class="com.sschen.ioclearning.LiuDeHua"></bean> <bean id="moAttack" class="com.sschen.ioclearning.MoAttack"> <property name="geLi" ref="geli"></property> </bean> </beans>在导演类中获取配置节点中内容,调用角色进行表演
代码 导演类获取配置
public class Director { private String userName = "FengXiaoGang"; public void directMovie() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Bean.xml"); MoAttack moAttack = applicationContext.getBean("moAttack", MoAttack.class); moAttack.cityGateAsk(); } }如此就真正实现了同角色实际扮演者的解耦,将这部分工作交给Spring配置来实现。在容器启动时,Spring根据配置文件的描述信息,自动实例化Bean并完成依赖关系的装配,从容器中即可返回准备就绪的Bean实例,后续可直接使用。
那么为什么Spring能够通过仅仅在配置文件中配置的bean节点,就能实例化并且装配好程序所用的bean呢?这就应改归功于Java语言本身的类反射功能。
相关文章推荐
- 【java基础】IOC介绍及其简单实现
- Java IOC介绍及其简单实现
- IOC介绍及其简单实现,Struts+Spring
- IOC介绍及其简单实现
- IOC介绍及其简单实现
- IOC介绍及其简单实现
- --------------------9 以上介绍了一个最简单的http交互的java实现----------------------------------
- java基础实现简单的用户登陆功能
- 黑马程序员:Java基础总结----子接口 List<E>及其实现类
- 简单介绍java Enumeration 很多类都是实现了这个接口的 比如StringTokenizer类 方法很类似
- IOC的简单实现及其意义.
- spring基础学习之Ioc-反射简单介绍(四)
- RabbitMQ学习及实践2---介绍及简单Java实现
- Java Applet简单介绍及其使用实例(键人岐)
- Java基本功练习十七GUI(图形用户界面基础【基本概念及其使用、三种布局管理器实现同样的框架练习】)
- Java基础---Java---基础加强---内省的简单运用、注解的定义与反射调用、 自定义注解及其应用、泛型及泛型的高级应用、泛型集合的综合
- 【C#基础】方法及其调用、构造方法、out与ref参数及其返回值、方法重载、静态方法等简单介绍
- 使用Java实现简单的server/client回显功能的方法介绍
- Java基础---Java---基础加强---内省的简单运用、注解的定义与反射调用、 自定义注解及其应用、泛型及泛型的高级应用、泛型集合的综合
- Java基础学习笔记(七)Set接口及其实现子类