spring IOC 具体实现原理,模拟代码

IOC 控制反转

其实spring底层用的是工厂设计模式,
下面逐步实现控制反转。

案列

  • 目录结构
    在这里插入图片描述
    在包com.westos2.ioc下新建
  1. ATest类
  2. BTest类,类中属性有ATest aTest;
    需求生产一个A对象,生产一个B对象(内包含A)。
  • 代码ATest
package com.westos2.ioc;

public class ATest {
    public void show(){
        System.out.println("我是A");
    }
}

  • 代码BTest
package com.westos2.ioc;

public class BTest {
    private ATest aTest;

    public ATest getaTest() {
        return aTest;
    }

    public void setaTest(ATest aTest) {
        this.aTest = aTest;
    }

    public void show(){
        System.out.println("我是B,我准备调用A.show()");
        aTest.show();
    }

    @Override
    public String toString() {
        return "BTest{" +
                "aTest=" + aTest +
                '}';
    }
}

  • ClassBean类,用于封装要创建实例类的信息

package com.westos2.ioc;

import java.util.Map;

public class ClassBean {
    private String name;
    private String id;
    private Map<String,Object> map;

    public ClassBean() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    @Override
    public String toString() {
        return "ClassBean{" +
                "name='" + name + '\'' +
                ", id='" + id + '\'' +
                ", map=" + map +
                '}';
    }
}

Main类,用于创建对象,并测试代码


package com.westos2.ioc;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Main {
    //用于存储创建好的对象
    private static Map<String,Object> content =new HashMap<>();
    public static void main(String[] args) {
	//封装ATest类信息
        ClassBean classBean = new ClassBean();
        classBean.setId("a");
        classBean.setName("com.westos2.ioc.ATest");
        System.out.println(classBean);
	//封装BTest类信息
        ClassBean classBean2 = new ClassBean();
        classBean2.setId("b");
        classBean2.setName("com.westos2.ioc.BTest");
        Map<String, Object> map = new HashMap<>();
        //ATest表示属性名,a代表ATest类的id
        map.put("aTest","a");
        classBean2.setMap(map);
        System.out.println(classBean2);
	//创建ATest对象
        ATest o = (ATest)create(classBean);
        System.out.println("A对象:"+o);
	//创建BTest对象,此时BTest中的属性aTest还是null
        BTest o1 = (BTest) create(classBean2);
        System.out.println("B对象:"+o1);

        //装配对象BTest中的属性aTest
        createb(classBean2, content);
        System.out.println("装配后的B对象:"+o1);
    }



    public static Object create(ClassBean classBean){
        Object o;
        try {
            Class<?> aClass = Class.forName(classBean.getName());
            o = aClass.newInstance();
            //将已经创建好的存起来
            content.put(classBean.getId(),o);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void createb(ClassBean classBean,Map content){
        Map<String, Object> map = classBean.getMap();
        //如果类中有属性
        if (map!=null){
            Set<String> keys = map.keySet();
            for (String key : keys) {
                //给类中属性设值
                //content.get(classBean.getId())拿到目标类对象,即BTest
                //content.get(map.get(key)),用map中属性名对应的值(ATest类的id)拿到ATest对象
                //key属性名,用于下面方法中找到对应的set方法
                invoke(content.get(classBean.getId()),content.get(map.get(key)),key);
            }
        }
    }

    private static void invoke(Object tagert,Object value,String name) {
        Method[] methods = tagert.getClass().getMethods();
        //注意set方法名的大小写问题。
        String methodsName="set"+name;
        //System.out.println(methodsName);
        Method method1=null;
        for (Method method : methods) {
            if (method.getName().equals(methodsName)){
                method1=method;
            }
        }
        try {
            //给目标类(BTest)的属性aTest设置值
            method1.invoke(tagert,new Object[]{value});
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}


改进版

  • 上述代码是用ClassBean封装类的信息,现在用配置文件封装。

  • 上述代码复制一份放在ioc2包下

  • Main类变化如下,其他不变

package com.westos2.ioc2;

import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Main {
    private static Map<String, Object> content = new HashMap<>();

    public static void main(String[] args) throws Exception {
        init();
        Map<String, Object> factory = getFactory();
        ATest a = (ATest) factory.get("a");
        a.show();

        BTest b = (BTest) factory.get("b");
        b.getaTest().show();

    }
    public static Map<String,Object> getFactory(){
        return content;
    }

    public static void init() throws Exception {
        String s = System.getProperty("user.dir");
        //建一个json文件,放在maven项目的resources下为例
        InputStream in=new FileInputStream(new File("E:\\mavenProject\\_20190519dynastryproxy\\src\\main\\resources\\ioc.json"));
        //common-io jar包
        String s1 = IOUtils.toString(in, "utf-8");
        //json解析成ClassBean对象集合。
        List<ClassBean> classBeans = JSON.parseArray(s1, ClassBean.class);
        //遍历创建对象
        for (ClassBean classBean : classBeans) {
            content.put(classBean.getId(),create(classBean));
        }
        //遍历装配
        for (ClassBean classBean : classBeans) {
            createb(classBean,content);
        }
    }


    public static Object create(ClassBean classBean) {
        Object o;
        try {
            Class<?> aClass = Class.forName(classBean.getName());
            o = aClass.newInstance();
            content.put(classBean.getId(), o);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void createb(ClassBean classBean, Map content) {
        Map<String, Object> map = classBean.getMap();
        if (map != null) {
            Set<String> keys = map.keySet();
            for (String key : keys) {
                invoke(content.get(classBean.getId()), content.get(map.get(key)), key);
            }
        }
    }

    private static void invoke(Object tagert, Object value, String name) {
        Method[] methods = tagert.getClass().getMethods();
        String methodsName = "set" + name;
        Method method1 = null;
        for (Method method : methods) {
            if (method.getName().equals(methodsName)) {
                method1 = method;
            }
        }
        try {
            method1.invoke(tagert, new Object[]{value});
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

  • ioc.json
[
  {
    "id": "a",
    "name": "com.westos2.ioc2.ATest"
  },
  {
    "id": "b",
    "map": {
      "aTest": "a"
    },
    "name": "com.westos2.ioc2.BTest"
  }
]

spring下ioc的使用

  • 新建一个westos3.springioc包,将上面的ATest和BTest复制一下,

  • SpringUtils类

package com.westos3.springioc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringUtils {
    public static ApplicationContext context=null;

    static {
        //初始化spring,读取配置文件,maven项目,resources下的spring.xml
        context = new ClassPathXmlApplicationContext("spring.xml");
    }

    private SpringUtils() {
    }

    public static ApplicationContext getContext() {
        return context;
    }
}

  • Test类
package com.westos3.springioc;

public class Test {
    public static void main(String[] args) {
        BTest b = (BTest)SpringUtils.getContext().getBean("b");
        b.getaTest().show();
    }
}

resources目录下(与java文件夹平级)的spring.xml

<?xml version="1.0" encoding="utf-8" ?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
">

    <bean id="a" class="com.westos3.springioc.ATest"/>

    <bean id="b" class="com.westos3.springioc.BTest">
        <property name="aTest" ref="a"/>
    </bean>
</beans>


谢谢!

猜你喜欢

转载自blog.csdn.net/qq_43371004/article/details/90347745
今日推荐