(一)工厂模式

从一个例子开始讲起:

首先我们建立一个Chinese.java类,该类的sayHelloWorld(String name)方法,用中文对名为name的人问好,其内容如下:

[java] view plaincopyprint?
  1. public class Chinese {
  2. /**-- 用中文对某人问好. --*/
  3. publicvoid sayHelloWorld(String name) {
  4. String helloWorld = "你好," + name;
  5. System.out.println(helloWorld);
  6. }
  7. }

下面我们接着建立一个American.java类,该类的sayHelloWorld(String name)方法,用英文对名为name的人问好,其内容如下:下面我们接着建立一个American.java类,该类的sayHelloWorld(String name)方法,用英文对名为name的人问好,其内容如下:

[html] view plaincopyprint?
  1. publicclass American {
  2. /*-- 用英文对某人问好 --*/
  3. publicvoid sayHelloWorld(String name) {
  4. String helloWorld = "Hello," + name;
  5. System.out.println(helloWorld);
  6. }
  7. }

最后我们编写一个测试类对这两个类的sayHelloWorld(String name)方法进行测试,下面是该类的内容:

[java] view plaincopyprint?
  1. publicclass HelloWorldTest {
  2. /*-- 测试Chinese和American的sayHelloWorld()方法 --*/
  3. publicstaticvoid main(String[] args) {
  4. Chinese chinese = new Chinese();
  5. chinese.sayHelloWorld("极度暴走");
  6. American american = new American();
  7. american.sayHelloWorld("jidubaozou");
  8. }
  9. }

现实生活中我们总是把同一类产品放在一个工厂中生产,消费者只需要告诉工厂自己需要这一类产品中的哪一种产品,工厂就能够生产出对应的产品,从而完成交易。

这里我们把上面例子中的HelloWorldTest类想象为消费者,而Chinese和American类想象为产品,根据上面的例子,我们可以看到每当HelloWorldTest这个消费者需要一个产品时都要去自己去生产(new),这样消费者就不得不去了解各个产品的内部结构及生产过程。显然对于消费者来说这样是很麻烦的。

而在程序设计领域中这个问题就叫做强耦合问题,HelloWorldTest类与Chinese和American这两个类都存在强耦合关系。设想一下,如果程序中的很多类都需要用到Chinese和American类这两个类,那么每个类就必须和这两个类强耦合,而且现实的项目中类似于Chinese这种类往往不仅两个,这样会使得整个程序的耦合度很高,增大程序的复杂度。这时我们就想到,能否也使用一个工厂来生产这些类,这样如果某个类需要用到工厂中的哪个类,就只要通过和工厂生产就行了,从而降低了整个程序的耦合度。

下面看看工厂模式是如何实现的:

首先建立接口类Human.java,其内容如下:

[java] view plaincopyprint?
  1. public interface Human {
  2. /** *//**
  3. * 对某人问好.
  4. * @param name 姓名
  5. */
  6. public void sayHelloWorld(String name);
  7. }

并将American.java类和Chinese.java类改为实现该接口,即类头分别改成:public class American implements Human和public class Chinese implements Human。

接着编写HumanFactory.java工厂类,其内容为:

[java] view plaincopyprint?
  1. public class HumanFactory {
  2. /** *//**
  3. * 通过类型字段获取人的相应实例
  4. * @param type 类型
  5. * @return 返回相应实例
  6. */
  7. public Human getHuman(String type) {
  8. if ("chinese".equals(type)) {
  9. return new Chinese();
  10. } else {
  11. return new American();
  12. }
  13. }
  14. }

最后我们还需要修改测试类HelloWorld.java类,修改后的内容如下:

[java] view plaincopyprint?
  1. public class HelloWorldTest {
  2. /** *//**
  3. * 测试sayHelloWorld()方法.
  4. * @param args
  5. */
  6. public static void main(String[] args) {
  7. HumanFactory factory = new HumanFactory();
  8. Human human1 = factory.getHuman("chinese");
  9. human1.sayHelloWorld("极度暴走");
  10. Human human2 = factory.getHuman("american");
  11. human2.sayHelloWorld("jidubaozou");
  12. }
  13. }

通过上面的例子可以看到,使用工厂模式实现的方式, HelloWorldTest 不再与Chinese类和American类耦合,而只是和他们共同的接口耦合,从而很大程度的降低的程序的耦合性。到这里或许很多人会有一点疑虑,使用工厂模式的HelloWorldTest 类也是需要耦合两个类(即HumanFactory 类和Human 接口)那么为什么能说降低耦合度呢,这就要是何时要使用工厂模式的问题了。假如类似于我们这个例子,HumanFactory 这个工厂只生产两个类,那的确没有什么必要使用工厂模式,但是现实的项目中往往有更多和Chinese类类似的类,比如English,Japanese,这时候就能体现出工厂模式的优势了

 (二)Spring IOC的原理

首先我们来讲下为什么要引入IOC:

假设上面举例的那个程序已经部署到服务器中,并已经上线运行,这时项目来了这样一个新需求:增加一个Japanese类,并且在HelloWorldTest 类中调用Japanese的sayHelloWorld方法。在没有引入IOC之前,很显然我们为了这个新需求,必须把项目停止下来,然后从新编译HumanFactory 和HelloWorldTest这两个类,最后再重新上线运行。

而使用IOC,则能够在不重新编译部署的情况下实现上面的新需求!

那么我们来看一下IOC是去怎么实现这个新需求的:

首先我们在com.human包内创建一个Japanese类:

[java] view plaincopyprint?
  1. public class Japanese implements Human{
  2. private String name;
  3. private String age;
  4. public void sayHelloWorld(String string){
  5. System.out.println("你好,"+string);
  6. }
  7. public String getAge() {
  8. return age;
  9. }
  10. public void setAge(String age) {
  11. this.age = age;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. }

然后对HelloWorldTest 类做如下修改

[java] view plaincopyprint?
  1. public class HelloWorldTest {
  2. public static void main(String[] args) {
  3. ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
  4. BeanFactory beanFactory=ctx.getBeanFactory();
  5. Human human=beanFactory.getBean("human");
  6. human.sayHelloWorld("极度暴走");
  7. }
  8. }

然后我们在beans.xml中做如下配置:

[html] view plaincopyprint?
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <bean id="human" class="com.human.Japanese">
  4. <property name="name">
  5. <value>漩涡鸣人</value>
  6. </property>
  7. <property name="password">
  8. <value>22</value>
  9. </property>
  10. <pre class="html" name="code"></bean>
  11. </beans></pre>
  12. <p><br>
  13. 这样,HelloWorldTest 便会去调用Japanese类的sayHelloWorld()方法;用这种形式,我们只要修改beans.xml的配置便可以改变HelloWorldTest 类中human对象,并且不需要重新部署项目,这样就实现了human对象的热拔插。</p>
  14. <p>从上面的代码可以看到spring IOC的这种实现方式主要是靠BeanFactory这个类,那么这个BeanFactory到底有什么神奇之处呢?</p>
  15. <p>下面让我们模拟实现一个BeanFactory:</p>
  16. <p><br>
  17. </p>
  18. <pre class="java" name="code">import java.io.InputStream;
  19. import java.lang.reflect.Method;
  20. import java.util.HashMap;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import org.dom4j.Attribute;
  24. import org.dom4j.Document;
  25. import org.dom4j.Element;
  26. import org.dom4j.io.SAXReader;
  27. /** *//**
  28. * bean工厂类.
  29. */
  30. public class BeanFactory {
  31. private Map<String, Object> beanMap = new HashMap<String, Object>();
  32. /** *//**
  33. * bean工厂的初始化.
  34. * @param xml xml配置文件
  35. */
  36. public void init(String xml) {
  37. try {
  38. //读取指定的配置文件
  39. SAXReader reader = new SAXReader();
  40. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  41. //从class目录下获取指定的xml文件
  42. InputStream ins = classLoader.getResourceAsStream(xml);
  43. Document doc = reader.read(ins);
  44. Element root = doc.getRootElement();
  45. Element foo;
  46. //遍历bean
  47. for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
  48. foo = (Element) i.next();
  49. //获取bean的属性id和class
  50. Attribute id = foo.attribute("id");
  51. Attribute cls = foo.attribute("class");
  52. //利用Java反射机制,通过class的名称获取Class对象
  53. Class bean = Class.forName(cls.getText());
  54. //获取对应class的信息
  55. java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
  56. //获取其属性描述
  57. java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
  58. //设置值的方法
  59. Method mSet = null;
  60. //创建一个对象
  61. Object obj = bean.newInstance();
  62. //遍历该bean的property属性
  63. for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
  64. Element foo2 = (Element) ite.next();
  65. //获取该property的name属性
  66. Attribute name = foo2.attribute("name");
  67. String value = null;
  68. //获取该property的子元素value的值
  69. for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
  70. Element node = (Element) ite1.next();                                                                                           value = node.getText();
  71. break;
  72. }
  73. for (int k = 0; k < pd.length; k++) {
  74. if (pd[k].getName().equalsIgnoreCase(name.getText())) {                                                                         mSet = pd[k].getWriteMethod();
  75. //利用Java的反射机制调用对象的某个set方法,并将值设进去
  76. mSet.invoke(obj, value);
  77. }
  78. }
  79. }
  80. //将对象放入beanMap中,其中key为id值,value为对象
  81. beanMap.put(id.getText(), obj);
  82. }
  83. } catch (Exception e) {
  84. System.out.println(e.toString());
  85. }
  86. }
  87. /** *//**
  88. * 通过bean的id获取bean的对象.
  89. * @param beanName bean的id
  90. * @return 返回对应对象
  91. */
  92. public Object getBean(String beanName) {
  93. Object obj = beanMap.get(beanName);
  94. return obj;
  95. }
  96. /** *//**
  97. * 测试方法.
  98. * @param args
  99. */
  100. public static void main(String[] args) {
  101. BeanFactory factory = new BeanFactory();
  102. factory.init("bean.xml");
  103. Human human= (Human) factory.getBean("human");
  104. human.sayHelloWorld("极度暴走");
  105. System.out.println("Name=" + human.getName());
  106. System.out.println("age=" + human.getAge());
  107. }
  108. }
  109. </pre>
  110. <p><br>
  111. </p>
  112. <p>测试方法的执行结果:你好,极度暴走</p>
  113. <p>漩涡鸣人</p>
  114. <p>22</p>
  115. <p> </p>
  116. <p>总结:从上面的代码可以看出Spring的bean工厂主要实现了以下几个步骤</p>
  117. <p>1.解析配置文件(bean.xml)</p>
  118. <p>2.使用反射机制动态加载每个class节点中配置的类</p>
  119. <p>3.为每个class节点中配置的类实例化一个对象</p>
  120. <p>4.使用反射机制调用各个对象的seter方法,将配置文件中的属性值设置进对应的对象</p>
  121. <p>5.将这些对象放在一个存储空间(beanMap)中</p>
  122. <p>6.使用getBean方法从存储空间(beanMap)中取出指定的JavaBean</p>
  123. <p> </p>
  124. <p>PS:IOC的标准定义:</p>
  125. <p>(Inversion of Control) </p>
  126. <p>  中文译为: 控制反转</p>
  127. <p>  IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。</p>
  128. <p> </p>
  129. <p> </p>
  130. <pre></pre>
  131. <pre></pre>
  132. <pre></pre>
  133. <pre></pre>
  134. <pre></pre>
  135. <pre></pre>
  136. <pre></pre>
  137. <pre></pre>
  138. <pre></pre>
  139. <pre></pre>
  140. <pre></pre>
  141. <div style="padding-top:20px">
  142. <p style="font-size:12px;">版权声明:本文为博主原创文章,未经博主允许不得转载。</p>
  143. </div>

解析Spring IOC原理——工厂模式与反射机制的综合应用相关推荐

  1. java 反射 工厂模式_Java反射机制demo(七)—反射机制与工厂模式

    Java反射机制demo(七)-反射机制与工厂模式 工厂模式 简介 工厂模式是最常用的实例化对象模式. 工厂模式的主要作用就是使用工厂方法代替new操作. 为什么要使用工厂模式?直接new不好吗? 直 ...

  2. Spring Ioc原理解析

    Spring Ioc原理解析 IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦 ...

  3. Spring Ioc原理及解析

    IOC简介 IoC是Inversion of Control的缩写,多数书籍翻译成"控制反转",还有些书籍翻译成为"控制反向"或者"控制倒置" ...

  4. Spring IOC 原理解析

    Spring IOC 原理 ? IOC DI(依赖注入) **DI注入的几种方式** IOC容器 IOC原理 要想理解IOC,就需要知道一下IOC.DI 和IOC容器都是干什么的 IOC spring ...

  5. spring ioc原理分析

    spring ioc原理分析 spring ioc 的概念 简单工厂方法 spirng ioc实现原理 spring ioc的概念 ioc: 控制反转 将对象的创建由spring管理.比如,我们以前用 ...

  6. Spring IOC 原理

    Spring IOC原理 IOC理解 自己写的简单的IOC容器 IOC的原理 定位.加载.注册 基于XML配置的IOC容器初始化 1.寻找入口 2.获取配置路径 3.开始启动 4.创建容器 5.载入配 ...

  7. IOC和工厂模式的区别

    Spring的IOC和工厂模式的区别 IOC是使用了反射的技术来动态的生成对象 工厂模式的对象生成是提前在工厂类中定死的 IOC更加灵活 IoC--Inversion of Control 控制反转 ...

  8. 控制反转(IoC) ? 工厂模式?

    不知道大家还记不记得当年程杰的<大话设计模式>了,最近一直想搞明白控制反转到底是怎么回事,刚刚觉得高大上了一点,然后再进一步去学习去对比的时候才发现,以前早就接触过这类的思想,设计原则的依 ...

  9. spring ioc原理解析

    概述 Spring IOC控制反转,分为两个方面解释: 控制:对象对于内部成员的控制 反转:将之前对象管理自己内部成员,转变为ioc容器管理,目的是接耦 IOC的好处是: 无需手动创建,拿来就用 享受 ...

最新文章

  1. 浅析Spring——控制反转IoC
  2. FFT2 图像二维FFT含义解释
  3. access 按日期分列_excel的分列功能居然这么强大,赶紧收藏起来
  4. 关于保存到session里的信息
  5. appbarlayout 折叠后 不允许滑动_还在纠结要不要建阳光房?看看可折叠阳光房,或许你就能做选择了...
  6. Codeforces Round #432 B
  7. 5,线程池,进程池,协程,IO模型
  8. mini 打开窗口提交表单,按钮在页脚
  9. linux单用户模式single=1,Linux 单用户模式single mode
  10. 学习:配置hibernate
  11. JavaScript流程分支结构(1)
  12. Springboot项目中Pom.xml报错
  13. axure 倒计时_Axure 8.0实例 |自定义倒计时制作流程
  14. java网页作业提交_基于JAVA网上作业提交批改系统的设计(SQL)(含录像)
  15. ubuntu快速保存网页图片
  16. 最简单的共享列表服务器KissLists
  17. JAVA --银行卡正则校验工具类
  18. UMLChina建模竞赛第3赛季第3轮(《人月神话》专场)
  19. 计算机视觉中的算法幻想性视错觉
  20. 一致连续(uniform continuous)

热门文章

  1. 【数字信号处理】序列傅里叶变换 ( 序列傅里叶变换定义详细分析 | 证明单位复指数序列正交完备性 | 序列存在傅里叶变换的性质 | 序列绝对可和 → 序列傅里叶变换一定存在 )
  2. 【Android Gradle 插件】settings.gradle 配置文件 ( 配置基本作用 | include 函数用法 | 目录层级配置 | 修改 Module 模块构建脚本名称 )
  3. 【Groovy】编译时元编程 ( AST 语法树分析 | ClassNode 根节点 | 方法 Methods 节点 | 字段 Fields 节点 | 属性 Properties 节点 )
  4. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )
  5. 【错误记录】Android Studio 编译报错 ( cannot open this project, please retry with version 4.2 or newer. )
  6. 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )
  7. 【流媒体开发】VLC Media Player - Android 平台源码编译 与 二次开发详解 (提供详细800M下载好的编译源码及eclipse可调试播放器源码下载)
  8. Ajax实现局部数据交互的一个简单实例
  9. 网站真分页js代码该怎么写? 1
  10. CentOS下php安装mcrypt扩展