Spring IOC的Bean对象的实例化

问题:Spring是如何通过getBean方法获取到指定的类

大致流程:

  1. 创建对应的MyBean类提供id和class属性
  2. 创建实体类,实现通过配置文件解析到id和class属性,然后利用反射在找到指定的类

实现过程

1.手动创建Spring的配置文件,其中有两个标签:<beans>和<bean>,其中id属性是唯一值一般是实体类的首字母小写,class是实体类的绝对地址

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id="userService" class="com.spring.Service.UserService">

    </bean>
    <bean id="userDao" class="com.spring.DAO.UserDao">

    </bean>
</beans>

2.创建MyBean类,该类有id和class两个属性并提供构造方法和对应的get、set方法

package com.spring.Utils;

/**
 * 对应Spring.xml文件中的beans标签
 *
 */
public class MyBean {

    private String id;
    private String clazz;

    public MyBean() {
    }

    public MyBean(String id, String clazz) {
        this.id = id;
        this.clazz = clazz;
    }

    public String getId() {
        return id;
    }

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

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }
}

3.创建实现类

Tips
1.在此处简述一下实现类通过加载spring.xml获取指定类的大致过程
2.MyFactory接口提供getBean方法通过传入id属性值获取对应的类,MyClassPathXmlApplicationContext类继承MyFactory实现getBean方法

通过带参构造器得到配置文件
通过dom4j解析xml文件,得到一个List集合(存放bean标签的id和class属性值)
通过反射得到对应的实例化对象放置在Map中(遍历list集合,通过获取对应的class属性利用Class.forName(class).newIntance()得到实例化对象)
通过id属性值获取指定的实例化对象
package com.spring.Utils;

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


import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 模拟Spring的实现
 */

public class MyClassPathXmlApplicationContext implements MyFactory {

    //存放从配置文件读取到的bean标签的id和class属性
    private List<MyBean> beanList;
    //存放实例化好的对象,通过id获取到对象
    private Map<String, Object> beanMap = new HashMap<>();


    /**
     * 通过带参构造器得到配置文件
     *
     * @param fileName
     */
    public MyClassPathXmlApplicationContext(String fileName) {
        //通过dom4j解析xml文件,得到一个List集合
        this.parseXml(fileName);
        //通过反射得到对应的实例化对象放置在Map中
        this.intanceBean();
    }

    private void parseXml(String fileName) {
        //1.获取解析器
        SAXReader saxReader = new SAXReader();
        //2.获取URL
        URL url = this.getClass().getClassLoader().getResource(fileName);
        try {
            //3.通过解析器解析配置文件
            Document document = saxReader.read(url);
            //4.获取标签
            XPath xPath = document.createXPath("beans/bean");
            //5.通过指定的语法解析文档对象,返回元素结合
            List<Element> elementList = xPath.selectNodes(document);
            //6.判断元素是否为空
            if (elementList != null && elementList.size() > 0) {
                //实例化beanList
                beanList = new ArrayList<>();
                //如果不为空则循环
                for (Element element : elementList) {
                    //8.获取bean标签元素的属性(id和class属性)
                    String id = element.attributeValue("id");
                    String clazz = element.attributeValue("class");
                    //9.获取MyBean对象,将id和clazz放到对象中,再将对象设置到MyBean集合中
                    MyBean myBean = new MyBean(id, clazz);
                    beanList.add(myBean);
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过反射得到对应的实例化对象,放置在Map集合中
     */
    private void intanceBean() {
        //1.判断beanList集合是否为空,不为空则遍历集合获取该对象的id和class属性
        if (beanList != null && beanList.size() > 0) {
            for (MyBean bean : beanList) {
                String id = bean.getId();
                String clazz = bean.getClazz();
                //2.通过反射得到实例化的对象
                Object object = null;
                try {
                    object = Class.forName(clazz).newInstance();
                    //3.将对应好的id和对象放置到map集合中
                    beanMap.put(id, object);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 通过id获取到对应Map中实例化好的对象,
     *
     * @param id
     * @return object
     */
    @Override
    public Object getBean(String id) {
        //通过id取到对应的对象
        Object object = beanMap.get(id);
        return object;
    }
}

4.测试

package com.spring.Test;

import com.spring.DAO.UserDao;
import com.spring.Service.UserService;
import com.spring.Utils.MyClassPathXmlApplicationContext;
import com.spring.Utils.MyFactory;

public class Main {
    public static void main(String[] args) {
        //得到工厂的实现对象
        MyFactory mc = new MyClassPathXmlApplicationContext("spring.xml");
        //得到对应的实例化对象
        UserService userService = (UserService) mc.getBean("userService");
        userService.printInfo();
        UserDao userDao = (UserDao) mc.getBean("userDao");
        userDao.showInfo();
    }
}

注意实现: SpringIOC中的实例化对象是单例

UserService userService = (UserService) mc.getBean("userService");
UserService userService2 = (UserService) mc.getBean("userService");
System.out.println(userService==userService2);//true,创建的两个对象是同一个对象
posted @ 2023-09-15 16:15  绯村拔剑斋  阅读(37)  评论(0)    收藏  举报  来源