IOC即inverse of control 控制反转

以前对象之间的引用是通过new来调用实现,有了Spring IOC,我们可以把对象之间的引用交给他来管理,这样就把控制权交给了Spring,所以就叫做控制反转。

Spring IOC的实现用到了设计模式:简单工厂,他也是从简单工厂进化而来的,下面我们看看Spring的IOC是如何进化来的。

简单工厂模式实现:

  1. package org;
  2. //抽象接口
  3. interface Fruit{
  4. public void eat();
  5. }
  6. //实现类A
  7. class Apple implements Fruit{
  8. public void eat(){
  9. System.out.println("吃苹果。");
  10. }
  11. }
  12. //实现类B
  13. class Orange implements Fruit{
  14. public void eat(){
  15. System.out.println("吃橘子");
  16. }
  17. }
  18. //工厂类
  19. class Factory{
  20. public static Fruit getInstance(String className){
  21. Fruit f=null;
  22. if(className.equals("apple")){
  23. f=new Apple();
  24. }
  25. if(className.endsWith("orange")){
  26. f=new Orange();
  27. }
  28. return f;
  29. }
  30. }
  31. public class FactoryDemo02 {
  32. public static void main(String args[]){
  33. Fruit f=Factory.getInstance("apple");
  34. f.eat();
  35. }
  36. }

反射+简单工厂

但是工厂类如果这样写的话,就有一个问题,如果增加了水果,比如香蕉,那么在工厂类里面也要进行相关的修改了,这样不合理,而java的反射机制可以解决这个问题


  1. package org1;
  2. interface Fruit {
  3. public void eat();
  4. }
  5. class Apple implements Fruit {
  6. public void eat() {
  7. System.out.println("吃苹果。");
  8. }
  9. }
  10. class Orange implements Fruit {
  11. public void eat() {
  12. System.out.println("吃橘子");
  13. }
  14. }
  15. class Factory {
  16. public static Fruit getInstance(String className) {
  17. Fruit f = null;
  18. try {
  19. f = (Fruit) Class.forName(className).newInstance();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. return f;
  24. }
  25. }
  26. public class CopyOfFactoryDemo03 {
  27. public static void main(String args[]) {
  28. Fruit f = Factory.getInstance("org1.Apple");
  29. f.eat();
  30. }
  31. }


利用java的反射机制,就能动态的实例化各种类了。 但是这个程序还是存在一个问题,就是主函数这里需要填入一个完整的类名称,不够方便,所以要增加配置文件来简化

  1. package org3;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.util.Properties;
  6. interface Fruit {
  7. public void eat();
  8. }
  9. class Apple implements Fruit {
  10. public void eat() {
  11. System.out.println("吃苹果。");
  12. }
  13. }
  14. class Orange implements Fruit {
  15. public void eat() {
  16. System.out.println("吃橘子");
  17. }
  18. }
  19. class Factory {
  20. public static Fruit getInstance(String className) {
  21. Fruit f = null;
  22. try {
  23. f = (Fruit) Class.forName(className).newInstance();
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. return f;
  28. }
  29. }
  30. class PropertiesOperate{
  31. private Properties pro=null;
  32. private File file=new File("d:"+File.separator+"fruit.properties");
  33. public PropertiesOperate(){
  34. this.pro=new Properties();
  35. if(file.exists()){
  36. try {
  37. pro.loadFromXML(new FileInputStream(file));
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. }
  41. }else{
  42. this.save();
  43. }
  44. }
  45. private void save(){
  46. this.pro.setProperty("apple","org3.Apple");
  47. this.pro.setProperty("orange", "org3.Orange");
  48. try {
  49. this.pro.storeToXML(new FileOutputStream(this.file),"Fruit");
  50. } catch (Exception e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. public Properties getProperties(){
  55. return this.pro;
  56. }
  57. }
  58. public class CopyOfFactoryDemo04 {
  59. public static void main(String args[]) {
  60. Properties pro=new PropertiesOperate().getProperties();
  61. Fruit f= Factory.getInstance(pro.getProperty("apple"));
  62. f.eat();
  63. }
  64. }


终极版本Spring IOC
加入配置文件问题就解决了,以后如果要增加新的水果类,都要在这个配置文件里面登记。这时我们可以说配置文件可以控制程序的执行,现在看起来有点像spring的ioc了。下面我们来看看Spring IOC是如何实现的。

  1. package test2;
  2. public class Person {
  3. private String name;
  4. private int age;
  5. private Grade grade;
  6. public String getName() {
  7. return name;
  8. }
  9. public Grade getGrade() {
  10. return grade;
  11. }
  12. public void setGrade(Grade grade) {
  13. this.grade = grade;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public int getAge() {
  22. return age;
  23. }
  24. public int getTotleGrade() {
  25. return grade.getEnglish()+grade.getMath();
  26. }
  27. }


  1. package test2;
  2. public class Grade {
  3. private int math;
  4. private int english;
  5. public int getMath() {
  6. return math;
  7. }
  8. public void setMath(int math) {
  9. this.math = math;
  10. }
  11. public int getEnglish() {
  12. return english;
  13. }
  14. public void setEnglish(int english) {
  15. this.english = english;
  16. }
  17. }



Bean.xml配置文件(该文件只要放在test2包里面就好了)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
  3. "http://www.springframework.org/dtd/spring-beans.dtd">
  4. <beans>//很多豆豆
  5. <bean id="Person" class="test2.Person">//第一个豆豆,是一个Person类,id名字随便取,还要写上类的全名
  6. <property name="name">//下面开始把这个类里面的所有属性列出来,并赋值,至于你说难道一定要赋值吗?我想可以,我刚学,不知道
  7. <value>小龙</value>//这里的名字是通过程序里面的set来赋值的,不信你去掉程序里面相关的set,就出错了
  8. </property>
  9. <property name="age">
  10. <value>23</value>
  11. </property>
  12. <property name="grade">//这里有点特别,这个grade变量是一个对象,和一般的变量要区别对待
  13. <ref local="Grade"/>//这里指向了本配置文件里面一个名字叫Grade(即id=Grade)的bean
  14. </property>
  15. </bean>
  16. <bean id="Grade" class="test2.Grade">//同上
  17. <property name="math">
  18. <value>99</value>
  19. </property>
  20. <property name="english">
  21. <value>59</value>
  22. </property>
  23. </bean>
  24. </beans>


Test类


  1. package test2;
  2. import org.springframework.beans.factory.BeanFactory;
  3. import org.springframework.beans.factory.xml.XmlBeanFactory;
  4. import org.springframework.core.io.ClassPathResource;
  5. import org.springframework.core.io.Resource;
  6. import test.ExampleBean;
  7. public class Test {
  8. public static void main(String args[]){
  9. Resource input = new ClassPathResource("test2/Bean.xml");//Bean.xml的路径
  10. System.out.println("resource is:" + input);
  11. BeanFactory factory = new XmlBeanFactory(input);//把input扔到工厂里面去,这个工厂就能为你提供实例了(我也不知道能不能这样说)
  12. Person person =(Person) factory.getBean("Person");//你要一个叫Person的东西,那好,工厂就去找“Person"给你
  13. Grade grade=(Grade)factory.getBean("Grade");
  14. System.out.println("姓名:"+person.getName());//person可以调用里面相关的方法,就相当于new了一个Person一样
  15. System.out.println("年龄:"+person.getAge());
  16. System.out.println("数学成绩:"+grade.getMath());
  17. System.out.println("英语成绩:"+grade.getEnglish());
  18. System.out.println("数学,英语总成绩:"+person.getTotleGrade());
  19. }
  20. }



如此看来,你在对比一开始的那个水果的程序,你会发现,spring配置文件,还是一个工厂,只不过换种形式一样,他管理所有的类,新建的类要到工厂里面去登记,不然就不能被主程序用,这就是为什么说ioc就是工厂模式的升级版。至于配置文件的书写,就跟堆积木一样。
---------------------------------
顺便提下,关于Spring读取配置文件的方法:
applicationcontext---
FileSystemXmlApplicationContext---这个方法是从文件绝对路径加载配置文
ClassPathXmlApplicationContext---这个方法是从classpath下加载配置文件(适合于相对路径方式加载)
XmlWebApplicationContext----专为web工程定制的方法,推荐Web项目中使用。
beanfactory---
ClassPathResource --- 从系统的类路径中加载 
FileSystemResource --- 从文件系统加载,比如说自己指定配置文件的全路径 
InputStreamResource --- 从输入流中加载 
ServletContextResource --- 从Servlet 上下文环境中加载 
UrlResource --- 从指定的Url加载

---------------------------------------------
BeanFactory和ApplicationContext的区别
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能: 
        • MessageSource, 提供国际化的消息访问 
        • 资源访问,如URL和文件 
        • 事件传播 
        • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层 
最主要的就是BeanFactory延迟加载,当使用到getBean的时候才会抛异常,而ApplicationContext在刚开始启动加载的时候就会抛出异常,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。

spring IOC 模拟实现的更多相关文章

  1. 手动模拟实现Spring IOC功能(基于javaConfig风格)

    以下文中spring特指spring frameWork项目,不含其它:如spring cloud等. 作为刚开始研究spring源码的小白,对于spring两大核心功能之一的IOC,虽说大致了解了B ...

  2. (反射+内省机制的运用)简单模拟spring IoC容器的操作

    简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...

  3. spring ioc aop 原理

    spring ioc aop 原理 spring ioc aop 的原理 spring的IoC容器是spring的核心,spring AOP是spring框架的重要组成部分. 在传统的程序设计中,当调 ...

  4. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  5. Spring IOC(三)依赖注入

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 1.AbstractBeanFactory ...

  6. Spring IOC容器基本原理

    2.2.1 IOC容器的概念IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IOC容器 ...

  7. Spring IOC(一)概览

    Spring ioc源码解析这一系列文章会比较枯燥,但是只要坚持下去,总会有收获,一回生二回熟,没有第一次,哪有下一次... 本系列目录: Spring IOC(一)概览 Spring IOC(二)容 ...

  8. springmvc 运行原理 Spring ioc的实现原理 Mybatis工作流程 spring AOP实现原理

    SpringMVC的工作原理图: SpringMVC流程 . 用户发送请求至前端控制器DispatcherServlet. . DispatcherServlet收到请求调用HandlerMappin ...

  9. spring IOC的实现原理

    姓名:陈中娇     班级:软件151 1. IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应 ...

随机推荐

  1. 十五分钟介绍 Redis数据结构

    下面是一个对Redis官方文档<A fifteen minute introduction to Redis data types>一文的翻译,如其题目所言,此文目的在于让一个初学者能通过 ...

  2. Linux 源代码在线(http://lxr.linux.no/linux/)。

    LXR 是一个通用的源代码索引器和交叉引用器 它提供了一个基于 web 的可浏览任意定义以及任意标识的用法. 它支持很多种语言. LXR 曾经被作为 “Linux 交叉引用器” 但是已经被证明它可以用 ...

  3. Redis学习之路(006)- Redis学习手册(Hashes数据类型)

    一.概述: 我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器.所以该类型非常适合于存储值对象的信息.如Username.Password和Ag ...

  4. 归并排序(C++实现)

         归并排序是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件.常见的归并排序有两路归并排序(Merge Sort),多相归并排序(Polyph ...

  5. POJ 2230 Watchcow (欧拉回路)

    Watchcow Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 5258   Accepted: 2206   Specia ...

  6. process credentials(三)

    主要内容包括: 1.进程描述符中Realtime Mutex相关数据结构的初始化 2.子进程如何复制父进程的credentials 3.per-task delay accounting的处理 4.子 ...

  7. JavaSE入门学习20:Java面向对象之接口(interface)(一)

    一Java接口 接口(英文:interface)是抽象方法和常量值的集合,在Java编程语言中是一个抽象类型,接口通常以interface来声 明.类是一种详细实现体.而接口定义了某一批类所须要遵守的 ...

  8. mongodb c++ driver 2.0编译使用

    安装boost1.48.0 在boost的官网下载boost1.48.0,链接例如以下: http://sourceforge.net/projects/boost/files/boost/1.48. ...

  9. mac 上运行cassandra出现的java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException: : : unknown error错误解决方法

    mac 上运行cassandra出现的java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostExce ...

  10. GitHub 上值得推荐的开源电子书

    GitHub 上值得推荐的开源电子书 开源不仅局限于软件领域,开源同样意味着自由选择的权利和对知识开放的追求. 可以参照这篇文章,已附上所有超链接编程类开放书籍荟萃-Linux Story 语言无关类 ...