Spring深入浅出(二)IOC详解

来源:互联网 发布:数控铣床编程跑车图案 编辑:程序博客网 时间:2024/06/05 07:16
  1. IOC即inverse of control 控制反转
    1. 反射简单工厂
    2. 反射简单工厂xml配置文件
    3. 终极版本Spring IOC

IOC即inverse of control 控制反转

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

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

简单工厂模式实现:
[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-weight: normal;">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. }</span>  

反射+简单工厂

但是工厂类如果这样写的话,就有一个问题,如果增加了水果,比如香蕉,那么在工厂类里面也要进行相关的修改了,这样不合理,而java的反射机制可以解决这个问题
[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package org1;  
  2.   
  3. interface Fruit {  
  4.     public void eat();  
  5. }  
  6.   
  7. class Apple implements Fruit {  
  8.     public void eat() {  
  9.         System.out.println("吃苹果。");  
  10.     }  
  11. }  
  12.   
  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.         try {  
  23.             f = (Fruit) Class.forName(className).newInstance();  
  24.         } catch (Exception e) {  
  25.             e.printStackTrace();  
  26.         }  
  27.         return f;  
  28.     }  
  29. }  
  30.   
  31. public class CopyOfFactoryDemo03 {  
  32.     public static void main(String args[]) {  
  33.         Fruit f = Factory.getInstance("org1.Apple");  
  34.         f.eat();  
  35.     }  
  36. }  

反射+简单工厂+xml配置文件

利用java的反射机制,就能动态的实例化各种类了。 但是这个程序还是存在一个问题,就是主函数这里需要填入一个完整的类名称,不够方便,所以要增加配置文件来简化
[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package org3;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.util.Properties;  
  7.   
  8. interface Fruit {  
  9.     public void eat();  
  10. }  
  11.   
  12. class Apple implements Fruit {  
  13.     public void eat() {  
  14.         System.out.println("吃苹果。");  
  15.     }  
  16. }  
  17.   
  18. class Orange implements Fruit {  
  19.     public void eat() {  
  20.         System.out.println("吃橘子");  
  21.     }  
  22. }  
  23.   
  24. class Factory {  
  25.     public static Fruit getInstance(String className) {  
  26.         Fruit f = null;  
  27.         try {  
  28.             f = (Fruit) Class.forName(className).newInstance();  
  29.         } catch (Exception e) {  
  30.             e.printStackTrace();  
  31.         }  
  32.         return f;  
  33.     }  
  34. }  
  35.   
  36. class PropertiesOperate{  
  37.     private Properties pro=null;  
  38.     private File file=new File("d:"+File.separator+"fruit.properties");  
  39.       
  40.     public PropertiesOperate(){  
  41.         this.pro=new Properties();  
  42.         if(file.exists()){  
  43.             try {  
  44.                 pro.loadFromXML(new FileInputStream(file));  
  45.             } catch (Exception e) {  
  46.                 e.printStackTrace();  
  47.             }  
  48.         }else{  
  49.             this.save();  
  50.         }  
  51.     }  
  52.     private void save(){  
  53.         this.pro.setProperty("apple","org3.Apple");  
  54.         this.pro.setProperty("orange""org3.Orange");  
  55.         try {  
  56.             this.pro.storeToXML(new FileOutputStream(this.file),"Fruit");  
  57.         } catch (Exception e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.     }  
  61.     public Properties getProperties(){  
  62.         return this.pro;  
  63.     }  
  64. }  
  65.   
  66. public class CopyOfFactoryDemo04 {  
  67.     public static void main(String args[]) {  
  68.         Properties pro=new PropertiesOperate().getProperties();  
  69.         Fruit f= Factory.getInstance(pro.getProperty("apple"));  
  70.         f.eat();  
  71.     }  
  72. }  

终极版本Spring IOC

加入配置文件问题就解决了,以后如果要增加新的水果类,都要在这个配置文件里面登记。这时我们可以说配置文件可以控制程序的执行,现在看起来有点像spring的ioc了。下面我们来看看Spring IOC是如何实现的。
[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package test2;  
  2.   
  3. public class Person {  
  4.     private String name;  
  5.     private int age;  
  6.     private Grade grade;  
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.       
  11.     public Grade getGrade() {  
  12.         return grade;  
  13.     }  
  14.   
  15.     public void setGrade(Grade grade) {  
  16.         this.grade = grade;  
  17.     }  
  18.   
  19.     public void setName(String name) {  
  20.         this.name = name;  
  21.     }  
  22.   
  23.     public void setAge(int age) {  
  24.         this.age = age;  
  25.     }  
  26.   
  27.     public int getAge() {  
  28.         return age;  
  29.     }  
  30.   
  31.     public int getTotleGrade() {  
  32.         return grade.getEnglish()+grade.getMath();  
  33.     }  
  34. }  

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. package test2;  
  2.   
  3. public class Grade {  
  4.     private int math;  
  5.     private int english;  
  6.     public int getMath() {  
  7.         return math;  
  8.     }  
  9.     public void setMath(int math) {  
  10.         this.math = math;  
  11.     }  
  12.     public int getEnglish() {  
  13.         return english;  
  14.     }  
  15.     public void setEnglish(int english) {  
  16.         this.english = english;  
  17.     }  
  18. }  

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

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

如此看来,你在对比一开始的那个水果的程序,你会发现,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。
0 0
原创粉丝点击