小工具知识网

当前位置: 首页 > 行业知识 > 【Spring】模拟 Spring 框架

行业知识

【Spring】模拟 Spring 框架

2026-10-21 00:23:52 来源:互联网转载

Spring IoC 容器���实现原理:工厂模式 + 解析XML + 反射机制

我们给自己的框架起名为:mySpring(我的春天)

一、创建 mySpring 模块

引入dom4j 和 jaxen 的依赖,因为要使用它解析XML文件,还有 junit 依赖  

    4.0.0    org.myspringframework    mySpring    1.0.0            8        8                            org.dom4j            dom4j            2.1.3                            jaxen            jaxen            1.2.0                            junit            junit            4.13.2            test            

 

二、准备要管理的 Bean 

准备好我们要管理的Bean(这些Bean在将来开发完框架之后是要删除的)

注意包名,不要用org.myspringframework包,因为这些Bean不是框架内置的。是将来使用我们框架的程序员提供的

package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-11:07 * @since 1.0 */public class User {    private String name;    private int age;    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }    public void setName(String name) {        this.name = name;    }    public void setAge(int age) {        this.age = age;    }}
package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-11:08 * @since 1.0 */public class UserDao {    public void insert(){        System.out.println("mysql数据库正在保存用户数据.......");    }}
package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-11:09 * @since 1.0 */public class UserService {    private UserDao userDao;    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    public void save(){        userDao.insert();    }}

 

三、准备 myspring.xml 配置文件 

将来在框架开发完毕之后,这个文件也是要删除的。因为这个配置文件的提供者应该是使用这个框架的程序员

文件名随意,我们这里叫做:myspring.xml

文件放在类路径当中即可,我们这里把文件放到类的根路径下

                                            

使用value给简单属性赋值。使用ref给非简单属性赋值。  

 

四、编写 ApplicationContext 接口 

ApplicationContext 接口中提供一个 getBean() 方法,通过该方法可以获取 Bean 对象。

注意包名:这个接口就是 myspring 框架中的一员了。

package org.myspringframework.core;/** * Spring 应用上下文接口 * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.myspringframework.core * @date 2022-11-12-11:22 * @since 1.0 */public interface ApplicationContext {    /**     * 根据 beanName 获取 bean 对象     * @param beanName myspring 配置文件中 bean 标签的 id     * @return 对应的单例 bean 对象     */    Object getBean(String beanName);}

 

五、编写 ClassPathXmlApplicationContext

ClassPathXmlApplicationContext 是 ApplicationContext 接口的实现类。该类从类路径当中加载myspring.xml 配置文件  

package org.myspringframework.core;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.myspringframework.core * @date 2022-11-12-11:24 * @since 1.0 */public class ClassPathXmlApplicationContext implements ApplicationContext{    /**     * 解析 myspring 配置文件,初始化所有的 bean 对象     * @param configLocation spring 配置文件的路径     *                       (使用 ClassPathXmlApplicationContext 配置文件应当放到类路径下)     */    public ClassPathXmlApplicationContext(String configLocation) {    }    @Override    public Object getBean(String beanName) {        return null;    }}

 

六、确定采用 Map 集合存储 Bean

确定采用Map集合存储Bean实例

Map集合的key存储beanId,value存储Bean实例。Map

在ClassPathXmlApplicationContext类中添加Map属性

并且在ClassPathXmlApplicationContext类中添加构造方法,该构造方法的参数接收myspring.xml文件

同时实现getBean方法

package org.myspringframework.core;import java.util.HashMap;import java.util.Map;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.myspringframework.core * @date 2022-11-12-11:24 * @since 1.0 */public class ClassPathXmlApplicationContext implements ApplicationContext{    private Map singletonObjects = new HashMap();    /**     * 解析 myspring 配置文件,初始化所有的 bean 对象     * @param configLocation spring 配置文件的路径     *                       (使用 ClassPathXmlApplicationContext 配置文件应当放到类路径下)     */    public ClassPathXmlApplicationContext(String configLocation) {        // 解析 myspring.xml 配置文件,实例化 bean,将 bean 存放到 singletonObjects 集合中    }    /**     * 根据 beanName 在 singletonObjects 集合中获取对应的 bean 对象     * @param beanName myspring 配置文件中 bean 标签的 id     * @return 对应的 bean 对象     */    @Override    public Object getBean(String beanName) {        return singletonObjects.get(beanName);    }}

 

七、解析配置文件实例化所有 Bean 

在ClassPathXmlApplicationContext 的构造方法中解析配置文件,获取所有 bean 的类名,通过反射机制调用无参数构造方法创建 Bean。并且将 Bean 对象存放到 Map 集合中  

/** * 解析 myspring 配置文件,初始化所有的 bean 对象 * @param configLocation spring 配置文件的路径 *                       (使用 ClassPathXmlApplicationContext 配置文件应当放到类路径下) */public ClassPathXmlApplicationContext(String configLocation) {    try {        // 解析 myspring.xml 配置文件,实例化 bean,将 bean 存放到 singletonObjects 集合中        // dom4j 解析 XML 文件的核心对象        SAXReader reader = new SAXReader();        // 获取一个输入流,指向配置文件        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);        // 读文件        Document document = reader.read(in);        // 获取所有的 bean 标签        List nodes = document.selectNodes("//bean");        // 遍历 bean 标签        nodes.forEach(node -> {            try {                // 向下转型,为了使用 Element 接口中更丰富的方法                Element beanElement = (Element) node;                // 获取 id 属性                String id = beanElement.attributeValue("id");                // 获取 class 属性                String className = beanElement.attributeValue("class");                logger.info("bean id:" + id + ",bean  className:" + className);                // 使用反射机制创建对象,并存储到 Map 集合中,提前曝光                Class clazz = Class.forName(className);                Object bean = clazz.newInstance();                singletonObjects.put(id,bean);                // 记录日志                logger.info(singletonObjects.toString());            } catch (Exception e) {                e.printStackTrace();            }        });    } catch (Exception e) {        e.printStackTrace();    }}

 

八、测试能否获取到 Bean

@Testpublic void testMySpring(){    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myspring.xml");    Object user = applicationContext.getBean("user");    Object userDao = applicationContext.getBean("userDaoBean");    Object userService = applicationContext.getBean("userService");    System.out.println(user);    System.out.println(userDao);    System.out.println(userService);}

运行结果:

 

九、给 Bean 的属性赋值 

通过反射机制调用 set 方法,给 Bean 的属性赋值  

package org.myspringframework.core;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.Node;import org.dom4j.io.SAXReader;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.InputStream;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.myspringframework.core * @date 2022-11-12-11:24 * @since 1.0 */public class ClassPathXmlApplicationContext implements ApplicationContext{    private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);    private Map singletonObjects = new HashMap();    /**     * 解析 myspring 配置文件,初始化所有的 bean 对象     * @param configLocation spring 配置文件的路径     *                       (使用 ClassPathXmlApplicationContext 配置文件应当放到类路径下)     */    public ClassPathXmlApplicationContext(String configLocation) {        try {            // 解析 myspring.xml 配置文件,实例化 bean,将 bean 存放到 singletonObjects 集合中            // dom4j 解析 XML 文件的核心对象            SAXReader reader = new SAXReader();            // 获取一个输入流,指向配置文件            InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);            // 读文件            Document document = reader.read(in);            // 获取所有的 bean 标签            List nodes = document.selectNodes("//bean");            // 遍历 bean 标签            nodes.forEach(node -> {                try {                    // 向下转型,为了使用 Element 接口中更丰富的方法                    Element beanElement = (Element) node;                    // 获取 id 属性                    String id = beanElement.attributeValue("id");                    // 获取 class 属性                    String className = beanElement.attributeValue("class");                    logger.info("bean id:" + id + ",bean  className:" + className);                    // 使用反射机制创建对象,并存储到 Map 集合中,提前曝光                    Class clazz = Class.forName(className);                    Object bean = clazz.newInstance();                    singletonObjects.put(id,bean);                    // 记录日志                    logger.info(singletonObjects.toString());                } catch (Exception e) {                    e.printStackTrace();                }            });            nodes.forEach(node -> {                try {                    Element beanElement = (Element) node;                    // 获取 id 属性                    String id = beanElement.attributeValue("id");                    // 获取 class 属性                    String className = beanElement.attributeValue("class");                    // 获取 Class                    Class clazz = Class.forName(className);                    // 获取该 bean 标签下的所有 属性标签 property 标签                    for (Element property : beanElement.elements("property")) {                        // 获取属性名                        String propertyName = property.attributeValue("name");                        // 获取属性类型                        Field field = clazz.getDeclaredField(propertyName);                        logger.info("属性名:" + propertyName);                        // 获取 set 方法名                        String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);                        // 获取 set 方法                        Method setMethod = clazz.getDeclaredMethod(setMethodName, field.getType());                        // 获取具体的值                        String value = property.attributeValue("value");                        String ref = property.attributeValue("ref");                        Object realVal = null;                        // 值是简单类型                        if (value != null) {                            /**                             * 声明支持的简单类型                             * byte short int long float double boolean char                             * Byte Short Integer Long Float Double Boolean Character                             * String                             */                            // 属性类型名                            // String propertyTypeSimpleName = field.getType().getName(); 带有包名                            String propertyTypeSimpleName = field.getType().getSimpleName();                            switch (propertyTypeSimpleName){                                case "byte":                                    realVal = Byte.parseByte(value);                                    break;                                case "short":                                    realVal = Short.parseShort(value);                                    break;                                case "int":                                    realVal = Integer.parseInt(value);                                    break;                                case "long":                                    realVal = Long.parseLong(value);                                    break;                                case "float":                                    realVal = Float.parseFloat(value);                                    break;                                case "double":                                    realVal = Double.parseDouble(value);                                    break;                                case "boolean":                                    realVal = Boolean.parseBoolean(value);                                    break;                                case "char":                                    realVal = value.charAt(0);                                    break;                                case "Byte":                                    realVal = Byte.valueOf(value);                                    break;                                case "Short":                                    realVal = Short.valueOf(value);                                    break;                                case "Integer":                                    realVal = Integer.valueOf(value);                                    break;                                case "Long":                                    realVal = Long.valueOf(value);                                    break;                                case "Float":                                    realVal = Float.valueOf(value);                                    break;                                case "Double":                                    realVal = Double.valueOf(value);                                    break;                                case "Boolean":                                    realVal = Boolean.valueOf(value);                                    break;                                case "Character":                                    realVal = Character.valueOf(value.charAt(0));                                    break;                                case "String":                                    realVal = value;                                    break;                            }                            // 调用 set 方法                            setMethod.invoke(singletonObjects.get(id), realVal);                        }                        // 值是非简单类型                        if (ref != null) {                            // 调用 set 方法                            setMethod.invoke(singletonObjects.get(id), singletonObjects.get(ref));                        }                    }                } catch (Exception e) {                    e.printStackTrace();                }            });        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 根据 beanName 在 singletonObjects 集合中获取对应的 bean 对象     * @param beanName myspring 配置文件中 bean 标签的 id     * @return 对应的 bean 对象     */    @Override    public Object getBean(String beanName) {        return singletonObjects.get(beanName);    }}
@Testpublic void testMySpring(){    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myspring.xml");    Object user = applicationContext.getBean("user");    System.out.println(user);    UserService userService = (UserService) applicationContext.getBean("userService");    userService.save();}

运行结果:

 

十、打包发布 

将多余的类以及配置文件删除,使用 maven 打包发布  

 

十一、站在程序员角度使用 mySpring 框架

            org.myspringframework        mySpring        1.0.0                junit        junit        4.13.2        test    
package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-14:43 * @since 1.0 */public class Vip {    private String name;    private int age;    private double height;    @Override    public String toString() {        return "Vip{" +                "name='" + name + '\'' +                ", age=" + age +                ", height=" + height +                '}';    }    public void setName(String name) {        this.name = name;    }    public void setAge(int age) {        this.age = age;    }    public void setHeight(double height) {        this.height = height;    }}
package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-14:43 * @since 1.0 */public class OrderDao {    public void insert(){        System.out.println("正在保存订单信息......");    }}
package org.qiu.myspring.bean;/** * @author 秋玄 * @version 1.0 * @email qiu_2022@aliyun.com * @project Spring * @package org.qiu.myspring.bean * @date 2022-11-12-14:44 * @since 1.0 */public class OrderService {    private OrderDao orderDao;    public void setOrderDao(OrderDao orderDao) {        this.orderDao = orderDao;    }    public void generate(){        orderDao.insert();    }}
                                                    
@Testpublic void testMySpring(){    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myspring.xml");    Object vip = applicationContext.getBean("vip");    System.out.println(vip);    OrderService orderService = (OrderService) applicationContext.getBean("orderService");    orderService.generate();}

运行结果:  

 

一  叶  知  秋,奥  妙  玄  心

上一篇:VSCode超详细Vue模板设置教程!轻松上手!

下一篇:ps4怎么psn服务器?