手动实现Spring IOC功能

回顾

上篇文章已经演示了spring最基础的IOC功能 演示地址
先做一个简单的回顾。

public class DemoMain {
    public static void main(String[] args) {
        //创建Spring上下文加载bean.xml
        ApplicationContext app=new ClassPathXmlApplicationContext("bean.xml");
        //获取user实例
        User user =  (User)app.getBean("user");
        //打印user
        System.out.println(user);
    }
}
  1. 由以上代码可知,spring通过读取XML的内容(对象的包名类名、变量名称与值),通过反射动态的创建一个对象。

  2. 既然我们已经知道了原理,那么我们就可以通过这种方式自己手动实现一个简单版的Spring IOC功能

手动实现简单IOC功能

实现简单的IOC可以分为两步
不熟悉的童鞋可以点击超链接回顾基础(大神请绕道)

  1. 读取XML文件( XML读取回顾
  2. 通过反射动态的操作对象( 反射方法回顾

MySingleIOC// IOC 的实现类,实现了上面所说的2个步骤
Main// IOC 演示类
User// IOC 测试使用的 bean
Home // 同上
MySpring.xml // bean 配置文件
容器实现类 MySingleIOC的代码:

public class MySingleIOC {
    //模拟spring容器  用于保存bean的键值对的hashMap
    private Map<String, Object> beanMap = new HashMap<>();

    public MySingleIOC() { }

    //有参构造函数 初始化xml
    public MySingleIOC(String xmlName) throws Exception {
        loadbean(xmlName);
    }

    //私有方法加载bean
    private void loadbean(String xmlName) throws Exception {
        //第一步 读取 xml文件      
        InputStream resourceAsStream = MySingleIOC.class.getClassLoader().getResourceAsStream(xmlName);
        if (resourceAsStream == null) {
            //当找不到xml抛出异常
            throw new FileNotFoundException("该XML文件无法找到:" + xmlName);
        }
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
        Document parse = documentBuilder.parse(resourceAsStream);
        resourceAsStream.close();
        NodeList beanList = parse.getElementsByTagName("bean");
        //遍历bean标签
        for (int i = 0; i < beanList.getLength(); i++) {

            Node node = beanList.item(i);

            if (node instanceof Element) {
                Element el = (Element) node;

                String beanId = el.getAttribute("id");

                String beanClass = el.getAttribute("class");

                //第二步 反射动态获取对象   
                Class beanClazz = null;
                try {
                    //加载beanClass
                    beanClazz = Class.forName(beanClass);
                } catch (ClassNotFoundException e) {
                    e.getMessage();
                    return;
                }
                //创建Bean对象
                Object beanObj = beanClazz.newInstance();

                NodeList propertyList = el.getElementsByTagName("property");

                //遍历子标签property
                for (int j = 0; j < propertyList.getLength(); j++) {
                    Node item = propertyList.item(j);
                    if (item instanceof Element) {
                        Element ele = (Element) item;
                        //拿到变量名称
                        String name = ele.getAttribute("name");
                        //拿到变量值(不一定都是String类型下面要做转换)
                        String value = ele.getAttribute("value");

                        //通过反射将bean对象指定属性
                        Field declaredField = beanObj.getClass().getDeclaredField(name);
                        //将私有属性设置为可访问
                        declaredField.setAccessible(true);
                        //获取成员属性的类型名称,若非字符串类型,则需要做相应转换
                        String fieldTypeName = declaredField.getType().getName();

                        Object o = ParamType(fieldTypeName, value);
                        //为该成员属性赋值
                        declaredField.set(beanObj, o);
                        //将该字段属性设置值


                        beanMap.put(beanId, beanObj);

                    }
                }
            }

        }
    }

    //转换运行时参数类型(做简单演示,目前只有String Integer和int可扩展)
    private Object ParamType(String fieldTypeName, String value) {
        Object obj = null;
        //判断该成员属性是否为int或Integer类型
        if ("int".equals(fieldTypeName) || "java.lang.Integer".equals(fieldTypeName)) {
            //转换为int类型并为该成员属性赋值
            int intFieldValue = Integer.parseInt(value);
            obj = intFieldValue;

        }//判断该成员属性是否为String类型
        if ("java.lang.String".equals(fieldTypeName)) {
            //为该成员属性赋值
            obj = value;
        }//判断另外类型同理
        //if(){ }
        return obj;
    }

    //获取bean
    public Object getBean(String beanName) {
        Object bean = beanMap.get(beanName);
        if (bean == null) {
            throw new IllegalArgumentException("无法实例化该名称的bean,请确定名称是否正确 " + beanName);
        }

        return bean;
    }

}

测试使用的 bean 代码:

public class User {
    private String name;
    private Integer age;
    private String sex;
    //省略get、set方法
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
public class Home {
    private String country;
    private String province;
    private String homeCity;
    private String workCity;
    
    //省略get、set方法
   
    @Override
    public String toString() {
        return "Home{" +
                "country='" + country + '\'' +
                ", province='" + province + '\'' +
                ", homeCity='" + homeCity + '\'' +
                ", workCity='" + workCity + '\'' +
                '}';
    }
}

bean 配置文件MySpring.xml 内容:

<beans>
    <bean id="user" class="com.xiaoli.model.User">
        <property name="name" value="小立"></property>  <!--姓名-->
        <property name="age" value="22"></property>         <!--年龄-->
        <property name="sex" value=""></property>          <!--性别-->
    </bean>

    <bean id="home" class="com.xiaoli.model.Home">
        <property name="country" value="中国"></property>     <!--国家-->
        <property name="province" value="湖北"></property>     <!--省份-->
        <property name="homeCity" value="宜昌"></property>      <!--家乡城市-->
        <property name="workCity" value="杭州"></property>        <!--工作城市-->
    </bean>
</beans>



新建一个演示类DemoMain

public class DemoMain {

    public static void main(String[] args) throws  Exception{
        MySingleIOC ioc=new MySingleIOC("com/xiaoli/resouorce/MySpring.xml");
        User user = (User)ioc.getBean("user");
        System.out.println(user);
        Home home = (Home)ioc.getBean("home");
        System.out.println(home);

    }
}

得到结果:
在这里插入图片描述
与之前创建的spring项目结果相同;

以上是简单 IOC 实现的全部内容,难度不大,代码简洁。一个行业小白的理解,如果有错误,望指出,以便及时更正!谢谢!

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_44614710/article/details/86763077

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值