手写实现Spring IOC

4 篇文章 0 订阅

Spring中有两大核心内容:
一.IOC
二.AOP
今天我手写实现了IOC,来总结一下IOC的原理和实现方式

首先IOC底层所用到的技术
1>xml配置文件
2>dom4j解析xml
3>工厂设计模式
4>反射
5>内省
首先看一下IOC demo的流程图
p1
运行环境
1.jdk1.8,IntelliJ IDEA
ps(如果报错报找不到xml文件,请在target目录下的classes中手动复制)
首先我们构建bean类:

package com.example.writeioc.config;

import java.util.ArrayList;
import java.util.List;

public class Bean {
    private String name;
    private String className;

    private List<Property> properties = new ArrayList<Property>();

    public String getName() {
        return name;
    }

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

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public List<Property> getProperties() {
        return properties;
    }

    public void setProperties(List<Property> properties) {
        this.properties = properties;
    }

    @Override
    public String toString(){
        return "Bean[name = ]" + name + " , className = " + className + " , properties" + properties + " ]";
    }
}

然后实例写两个bean类

package com.example.writeioc.bean;

public class A {
    private String name;

    public String getName() {
        return name;
    }

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

package com.example.writeioc.bean;

public class B {
    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

然后写一个属性类(Property):

package com.example.writeioc.config;

public class Property {
    private String name;
    private String value;
    private String ref;

    public String getName() {
        return name;
    }

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

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getRef() {
        return ref;
    }

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

工厂接口:

package com.example.writeioc.main;

public interface BeanFactory {
    //根据bean的name获得bean对象
    Object getBean(String beanName);
}

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean name="A" class="com.example.writeioc.bean.A">
        <property name="name" value="Tom"></property>
    </bean>

    <bean name="B" class="com.example.writeioc.bean.B">
        <property name ="a" ref="A"></property>
    </bean>
</beans>

解析xml类(ConfigManager)

package com.example.writeioc.config;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConfigManager {
    //读取配置文件,并返回结果
    public static Map<String,Bean> getConfig(String path){
        Map<String,Bean> map = new HashMap<String,Bean>();
        //1创建解析器
        SAXReader saxReader = new SAXReader();
        //2加载配置文件
        InputStream is = ConfigManager.class.getResourceAsStream(path);
        Document document = null;
        try{
            document = saxReader.read(is);
        }catch (DocumentException e){
            e.printStackTrace();
            throw new RuntimeException("请检查xml配置");
        }
        //3定义xpath表达式去除所有bean元素
        //   //从任意节点选择名称为bean的节点   /从父节点选择  不写则是从当前节点选择
        String xpath = "//bean";
        //4对bean元素进行遍历
        List<Element> list = document.selectNodes(xpath);
        if(list != null){
            for(Element beanFile:list){
                Bean bean = new Bean();
                //将class,name等属性封装到bean对象中
                String name = beanFile.attributeValue("name");
                String className = beanFile.attributeValue("class");
                bean.setName(name);
                bean.setClassName(className);
                //获得bean元素下所有property元素,并将其属性封装到property子元素中
                List<Element> children = beanFile.elements("property");
                if(children != null){
                    for(Element child : children){
                        Property property = new Property();
                        String pName = child.attributeValue("name");
                        String pValue = child.attributeValue("value");
                        String pRef = child.attributeValue("ref");

                        property.setName(pName);
                        property.setRef(pRef);
                        property.setValue(pValue);
                        //将property对象封装到bean中
                        bean.getProperties().add(property);
                    }
                }
                //将bean对象封装到map中用于返回
                map.put(name,bean);
            }
        }
        return map;
    }
}

通过内省注入bean属性类:

package com.example.writeioc.utils;


import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

/**
 * @author Jet
 */
public class BeanUtils {
    public static Method getWriteMethod(Object beanObj,String name){
        //使用内省实现(基于java反射专门用于操作bean的属性的api)
        Method method = null;
        try{
            //1:分析bean对象-->BeanInfo
            BeanInfo beanInfo = Introspector.getBeanInfo(beanObj.getClass());
            //2:根据BeanInfo获取所有属性的描述器
            PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
            //3遍历描述器
            if(pds != null){
                for(PropertyDescriptor pd : pds){
                    //判断当前属性是否是我们要找的属性
                    String pName = pd.getName();
                    if(pName.equals(name)){
                        method = pd.getWriteMethod();
                    }
                }
            }
            //4返回找到的set方法
        }catch (IntrospectionException e){
            e.printStackTrace();
        }
        //如果没有找到-->抛出异常,提示用户检查是否创建对应的set方法
        if(method == null){
            throw new RuntimeException("请检查 " + name + "属性的set方法是否创建");
        }
        return method;
    }
}

装配初始化bean类(ClassPathXmlApplicationContext)

package com.example.writeioc.main;



import com.example.writeioc.config.Bean;
import com.example.writeioc.config.ConfigManager;
import com.example.writeioc.config.Property;
import com.example.writeioc.utils.BeanUtils;

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

public class ClassPathXmlApplicationContext implements BeanFactory{
    //配置信息
    private Map<String,Bean> config;
    //用一个Map来做spring的容器,放置spring所管理的对象
    private Map<String,Object> context = new HashMap<String,Object>();

    //在classPathXmlApplicationContext已创建就初始化容器

    @Override
    //根据Bean名称获得bean实例
    public Object getBean(String beanName){
        Object bean = context.get(beanName);
        return bean;
    }

    public ClassPathXmlApplicationContext(String path){
        //1读取配置文件获取初始化的bean的信息
        config  = ConfigManager.getConfig(path);

        //2遍历配置,初始化bean
        if(config != null){
            for(Map.Entry<String,Bean> en : config.entrySet()){
                  //获取配置中的bean信息
                String beanName = en.getKey();
                Bean bean = en.getValue();
                Object exsitBean = context.get(beanName);
                //因为createBean方法也会向context中放置bean,我们在初始化的时候先要查看是否已经存在bean
                //如果不存在再创建bean
                if(exsitBean == null){
                    //根据bean配置创建bean对象
                    Object beanObj = createBean(bean);
                    //3将初始化的bean放入容器
                    context.put(beanName,beanObj);
                }
            }
        }
    }
    //根据bean配置创建bean对象
    private Object createBean(Bean bean){
        //1获得要创建的bean的class
        String className = bean.getClassName();
        Class clazz = null;
        try{
            clazz = Class.forName(className);
        }catch (ClassNotFoundException e){
            e.printStackTrace();
            throw new RuntimeException("请检查bean的class配置 " + className);
        }
        //将class对应的对象创建出来
        Object beanObj = null;
        try{
            beanObj = clazz.newInstance();
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("bean没有空参构造" + className);
        }
        //2获得bean的属性,将其注入
        if(bean.getProperties() != null){
            for(Property property : bean.getProperties()){
                //1:简单value注入
                //获取要注入的属性名称
                String name = property.getName();
                //根据属性名称获得注入属性对应的set方法
                Method setMethod = BeanUtils.getWriteMethod(beanObj,name);
                //创建一个需要注入bean中的属性值
                Object parm = null;
                if(property.getValue() != null){
                    //获取要注入的属性值
                    String value = property.getValue();
                    parm = value;
                }
                //2其他bean的注入
                if(property.getRef() != null){
                    //先从容器中查找当前要注入的bean是否已经创建并放入容器中
                    Object exsitBean = context.get(property.getRef());
                    if(exsitBean == null){
                        //如果容器中不存在,则要创建
                        exsitBean = createBean(config.get(property.getRef()));
                        //将创建好的bean放入容器
                        context.put(property.getRef(),exsitBean);
                    }
                    parm = exsitBean;
                }
                //调用set方法注入
                try {
                    setMethod.invoke(beanObj,parm);
                }catch (Exception e){
                    e.printStackTrace();
                    throw new RuntimeException("bean的属性 " + parm + " 没有对应的set方法,或者参数不正确" + className);
                }
            }
        }
        return beanObj;
    }
}

源码地址:https://github.com/jet0605/IOC

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值