前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最像源码的自制版IOC

最像源码的自制版IOC

作者头像
姜同学
发布2022-10-27 16:48:50
3580
发布2022-10-27 16:48:50
举报
文章被收录于专栏:姜同学
代码语言: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='旺财'}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-06T,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档