看完这篇自己都可以写Spring IOC 容器 Bean 对象实例化--乐字节java

2021-04-23 18:26

阅读:684

标签:上下文   创建   version   rri   xpath语法   null   维护   actor   dom4j解析   

Spring IOC 容器 Bean 对象实例化模拟

思路:

  1. 定义Bean 工厂接口,提供获取bean方法
  2. 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
  3. 实现获取Bean方法

定义 Bean 属性对象

package com.xxxx.spring;

/**
 * bean对象
 *      用来接收配置文件中bean标签的id与class属性值
 */
public class MyBean {

    private String id; // bean对象的id属性值
    private String clazz; // bean对象的类路径

    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;
    }
}

如有疑问,可加入群:10803-55292,输入暗号13,即可有大佬帮助

添加 dom4j 坐标依赖


dom4j
    dom4j
    1.6.1jaxen
    jaxen
    1.1.6

准备自定义配置文件

spring.xml

定义 Bean 工厂接口

package com.xxxx.spring;

/**
 * Bean 工厂接口定义
 */
public interface MyFactory {
    // 通过id值获取对象
    public Object getBean(String id);
}

定义 Bean 接口的实现类

package com.xxxx.spring;

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的实现
 *  1、通过构造器得到相关配置文件
 *  2、通过dom4j解析xml文件,得到List   存放id和class
 *  3、通过反射实例化得到对象   Class.forName(类的全路径).newInstance(); 通过Map存储
 *  4、得到指定的实例化对象
 */
public class MyClassPathXmlApplicationContext implements BeanFactory {

    private Map beans = new HashMap(); // 实例化后的对象放入map
    private List myBeans; // 存放已读取bean 配置信息

    /* 1、通过构造器得到相关配置文件 */
    public MyClassPathXmlApplicationContext(String fileName) {

        /* 2、通过dom4j解析xml文件,得到List (存放id和class) */
        this.parseXml(fileName);

        /* 3、通过反射实例化得到对象Class.forName(类路径).newInstance();  通过Map存储 */
        this.instanceBean();

    }

    /**
     * 通过dom4j解析xml文件,得到List   存放id和class
     *  1、获取解析器
     *  2、得到配置文件的URL
     *  3、通过解析器解析xml文件(spring.xml)
     *  4、通过xpath语法,获取beans标签下的所有bean标签
     *  5、通过指定语法解析文档对象,返回集合
     *  6、判断集合是否为空,遍历集合
     *  7、获取标签元素中的属性
     *  8、得到Bean对象,将Bean对象设置到集合中
     * @param fileName
     */
    private void parseXml(String fileName) {
        // 1、获取解析器
        SAXReader reader = new SAXReader();
        // 2、得到配置文件的URL
        URL url = this.getClass().getClassLoader().getResource(fileName);
        try {
            // 3、通过解析器解析xml文件(spring.xml)
            Document document = reader.read(url);
            // 4、通过xpath语法,获取beans标签下的所有bean标签
            XPath xPath = document.createXPath("beans/bean");
            // 通过指定语法解析文档对象,返回集合
            List list = xPath.selectNodes(document);
            // 判断集合是否为空,遍历集合
            if (list != null && list.size() > 0) {
                myBeans = new ArrayList();
                for(Element el : list) {
                    // 获取标签元素中的属性
                    String id = el.attributeValue("id"); // id 属性值
                    String clazz = el.attributeValue("class"); // class 属性值
                    System.out.println(el.attributeValue("id"));
                    System.out.println(el.attributeValue("class"));
                    // 得到Bean对象
                    MyBean bean = new MyBean(id, clazz);
                    // 将Bean对象设置到集合中
                    myBeans.add(bean);
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过反射实例化得到对象  
     *  Class.forName(类的全路径).newInstance();  
     *  通过Map存储
     */
    private void instanceBean() {
        // 判断bean集合是否为空,不为空遍历得到对应Bean对象
        if (myBeans != null && myBeans.size() > 0) {
            for (MyBean bean : myBeans){                                      
                try {
                    // 通过类的全路径实例化对象
                    Object object = Class.forName(bean.getClazz()).newInstance();
                    // 将id与实例化对象设置到map对象中
                    beans.put(bean.getId(), object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 通过key获取map中的指定value
     * @param id
     * @return
     */
    @Override
    public Object getBean(String id) {
        Object object = beans.get(id);
        return object;
    }
}

测试自定义 IOC 容器

  1. 创建与配置文件中对应的Bean对象

    UserService.java

    package com.xxxx.service;
    
    public class UserService {
    
       public void test(){
           System.out.println("UserService Test...");
       }
    }

    AccountService.java

    package com.xxxx.service;
    
    public class AccountService {
    
       public void test(){
           System.out.println("AccountService Test...");
       }
    }
  2. 测试是否可以获取实例化的Bean对象

    package com.xxxx;
    
    import com.xxxx.spring.MyFactory;
    import com.xxxx.spring.MyClassPathXmlApplicationContext;
    import com.xxxx.service.AccountService;
    import com.xxxx.service.UserService;
    
    public class App {
    
       public static void main(String[] args) {
           MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml");
           // 得到实例化对象
           UserService userService = (UserService) factory.getBean("userService");
           userService.test();
    
           UserService userService2 = (UserService) factory.getBean("userService");
           System.out.println(userService+"=====" + userService2);
    
           AccountService accountService = 
           (AccountService)factory.getBean("accountService");
           accountService.test();
    
       }
    }

    ? Spring 容器在启动的时候 读取xml配置信息,并对配置的 bean 进行实例化(这里模拟的比较简单,仅用于帮助大家理解),同时通过上下文对象提供的 getBean() 方法拿到我们配置的 bean 对象,从而实现外部容器自动化维护并创建 bean 的效果。

技术图片

看完这篇自己都可以写Spring IOC 容器 Bean 对象实例化--乐字节java

标签:上下文   创建   version   rri   xpath语法   null   维护   actor   dom4j解析   

原文地址:https://blog.51cto.com/14819669/2509471


评论


亲,登录后才可以留言!