最像源码的自制版IOC

2022-10-27 16:48:50 浏览数 (3)

代码语言:javascript复制
概念

所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交 由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和生命周期的管理,而是在 需要时由Spring框架提供,这个由spring框架管理对象创建和生命周期的机制称之为控制反 转。而在 创建对象的过程中Spring可以依据配置对对象的属性进行设置,这个过称之为依赖注 入,也即DI。

代码语言:javascript复制
初代IOC的初始化过程

说人话就是先把XML配置文件加载成输入流,然后解析成为BeanDefinition对象(就是把xml上的东西映射成为一个对象),然后BeanFactory通过反射创建真正的对象

代码语言:javascript复制
手写IOC

自定义一个User类和一个Dog类

代码语言:javascript复制
package com.jmy.ioc;

public class User {
    private String name;
    private int age;
    private Dog dog;

    public User() {
    }

    public User(String name, int age, Dog dog) {
        this.name = name;
        this.age = age;
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "User{"  
                "name='"   name   '''  
                ", age="   age  
                ", dog="   dog  
                '}';
    }

    public void sayHello(){
        System.out.println("Hello world!");
    }
}

代码语言:javascript复制
package com.jmy.ioc;

public class Dog {
    private String name;

    public Dog() {
    }

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Dog{"  
                "name='"   name   '''  
                '}';
    }
}

xml文件转化为InputStream

代码语言:javascript复制
package com.jmy.ioc;

import java.io.InputStream;

// 此接口用于将xml文件转化为流的形式
public interface Resource {
    public InputStream getResource();
}

java
代码语言:javascript复制
package com.jmy.ioc;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class XmlResourceToStream implements Resource{

    private String xmlName;

    public XmlResourceToStream(String xmlName) {
        this.xmlName = xmlName;
    }

    @Override
    public InputStream getResource() {
        URL resource = this.getClass().getClassLoader().getResource(xmlName);
        InputStream inputStream = null;
        try {
            URLConnection urlConnection = resource.openConnection();
            inputStream = urlConnection.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return inputStream;
    }
}

抽象之后的XML对象BeanDefinition

代码语言:javascript复制
package com.jmy.ioc;

import java.util.concurrent.ConcurrentHashMap;

public class BeanDefinition {
    private String beanId; // xml中bean标签的id
    private String beanClassName; // xml中bean标签的class
    private Class beanClass; // xml中bean的字节码对象
    private Object bean; // bean对象
    private ConcurrentHashMap<String,Object> beanProperty; // xml中bean的属性

    public BeanDefinition(String className) {
        this.beanClassName = className;
    }

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public String getBeanId() {
        return beanId;
    }

    public void setBeanId(String beanId) {
        this.beanId = beanId;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(String beanClassName) {
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public ConcurrentHashMap<String, Object> getBeanProperty() {
        return beanProperty;
    }

    public void setBeanProperty(ConcurrentHashMap<String, Object> beanProperty) {
        this.beanProperty = beanProperty;
    }
}

如果value的值为引用类型需要我们标记一下

代码语言:javascript复制
package com.jmy.ioc;

// property标签如果是ref给予标记
public class BeanRefence {
    private String ref;

    public BeanRefence(String ref) {
        this.ref = ref;
    }

    public String getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref = ref;
    }
}

读取xml文件封装BeanDefinition

代码语言:javascript复制
package com.jmy.ioc;

// 读取配置文件定义bean
public interface BeanDefinitionReader {
    void loadResource(Resource resource);
}

代码语言:javascript复制
package com.jmy.ioc;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    ConcurrentHashMap<String, BeanDefinition> map;

    public XmlBeanDefinitionReader() {
        this.map = new ConcurrentHashMap<String, BeanDefinition>();
    }

    @Override
    public void loadResource(Resource resource) {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        InputStream inputStream = resource.getResource();
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(inputStream);
            this.registBeanDefinition(document);
            inputStream.close();
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }
    }

    private void registBeanDefinition(Document document) {
        Element root = document.getDocumentElement(); // 直接获取<beans>
        NodeList beanList = root.getElementsByTagName("bean"); // 获取所有的bean标签
        // 遍历所有的bean标签 为BeanDefinition注入属性
        for (int i = ; i < beanList.getLength(); i  ) {
            Node node = beanList.item(i);
            Element beanNode = (Element) node;
            String id = beanNode.getAttribute("id");
            String className = beanNode.getAttribute("class");

            BeanDefinition beanDefinition = new BeanDefinition(className);

            // 为bean注入属性
            this.injectProperties(beanDefinition, beanNode);
            // 注册bean
            map.put(id, beanDefinition);
        }

    }

    private void injectProperties(BeanDefinition beanDefinition, Element beanNode) {
        NodeList properties = beanNode.getElementsByTagName("property");
        ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
        if (properties != null) {
            for (int i = ; i < properties.getLength(); i  ) {
                Element property = (Element) properties.item(i);
                String name = property.getAttribute("name");
                String value = property.getAttribute("value");

                if (value != null && value.length() != ) {
                    map.put(name, value);
                } else {
                    String ref = property.getAttribute("ref");
                    map.put(name, new BeanRefence(ref));
                }

            }

            beanDefinition.setBeanProperty(map);
        }
    }

    public Map<String, BeanDefinition> getBeanDefinitionMap() {
        return map;
    }
}

BeanFactory创建对象并注入属性

代码语言:javascript复制
package com.jmy.ioc;

public interface BeanFactory {
    public Object getBean(String name);
}

代码语言:javascript复制
package com.jmy.ioc;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

// 真正的去创建bean对象并注入属性
public class InjectBeanFactory implements BeanFactory {

    private Map<String, BeanDefinition> beanDefinitionMap;
    private XmlBeanDefinitionReader beanDefinitionReader;

    public InjectBeanFactory(XmlBeanDefinitionReader beanDefinitionReader) {
        this.beanDefinitionReader = beanDefinitionReader;
        this.setBeanDefinitionMap(beanDefinitionReader.getBeanDefinitionMap());
    }

    public void setBeanDefinitionMap(Map<String, BeanDefinition> beanDefinitionMap) {
        this.beanDefinitionMap = beanDefinitionReader.getBeanDefinitionMap();
    }

    @Override
    public Object getBean(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        Object bean = beanDefinition.getBean();

        // 创建对象
        if (null == bean) {
            bean = this.doCreate(beanDefinition);
        }
        // 注入属性
        if (!beanDefinition.getBeanProperty().isEmpty()) {
            this.injectProperties(bean, beanDefinition.getBeanProperty());
        }

        return bean;
    }

    private void injectProperties(Object bean, ConcurrentHashMap<String, Object> beanProperty) {
        for (Map.Entry<String, Object> entry : beanProperty.entrySet()) {
            String fieldName = entry.getKey();
            // 通过反射获取属性
            try {
                Field field = bean.getClass().getDeclaredField(fieldName);
                // 暴力破解
                field.setAccessible(true);
                Object value = entry.getValue();
                if (value instanceof BeanRefence) {
                    field.set(bean, this.getBean(((BeanRefence) value).getRef()));
                } else {
                    String type = field.getType().getName();
                    if (type.equals("java.lang.String")) {
                        field.set(bean, entry.getValue());
                    } else if (type.equals("java.lang.Integer") || type.equals("int")) {
                        field.set(bean, Integer.valueOf((String) entry.getValue()));
                    }
                }

            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }


    private Object doCreate(BeanDefinition beanDefinition) {
        try {
            beanDefinition.setBean(Class.forName(beanDefinition.getBeanClassName()).newInstance());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return beanDefinition.getBean();
    }
}

创建一个自己的ApplicationContext整合前几步

代码语言:javascript复制
撒花

最后本来想要写一个单元测试但是IDEA今天貌似有一些不给力一单元测试就死机。。所以写个main函数运行一下算了!!

xml文件

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/util">


        <bean id="user" class="com.jmy.ioc.User">
            <property name="name" value="姜明阳"></property>
            <property name="age" value="22"></property>
            <property name="dog" ref="dog"></property>
        </bean>

        <bean id="dog" class="com.jmy.ioc.Dog">
            <property name="name" value="旺财"></property>
        </bean>
</beans>

主函数

代码语言:javascript复制
package com.jmy.ioc;

public class Test {
    public static void main(String[] args) {
        MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("application.xml");
        User user = (User) context.getBean("user");
        user.sayHello();
        System.out.println(user.getName());
        System.out.println(user.getDog());
       /*int[] arry = new int[]{1,2,3,4};
        for (int i = 0; i < arry.length; i  ) {
            System.out.println(arry[i]);
        }

       change(arry);
        for (int i = 0; i < arry.length; i  ) {
            System.out.println(arry[i]);
        }*/
    }

    /*static void change(int[] inarry) {
        inarry[0] = 666;
        inarry = new int[7];
    }*/
}

结果

代码语言:javascript复制
Hello world!
姜明阳
Dog{name='旺财'}

0 人点赞