• spring IOC 模拟实现



    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。

  • 相关阅读:
    16个最棒的jQuery视差滚动效果教程
    16个最棒的WordPress婚纱摄影网站主题
    2013年最受欢迎的16个HTML5 WordPress主题
    16个最佳PSD文件下载网站
    16个最热门的 Android Apps 推荐下载
    前端工程师应该都了解的16个最受欢迎的CSS框架
    16个最好并且实用的jQuery插件【TheTop16.com】
    16个最受欢迎的Magento电子商务主题【TheTop16.com】
    [Nunit] System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host
    WORD
  • 原文地址:https://www.cnblogs.com/signheart/p/a7e34295588e41c7d5fa8e45ee9f8b92.html
Copyright © 2020-2023  润新知