手写Spring(一)IOC之ClassPathXmlApplicationContext

该博客介绍了Spring框架中IOC容器的实现细节,包括BeanDefinition的创建、注册表(BeanDefinitionRegistry)的设计、XML配置文件的解析以及BeanFactory和ApplicationContext接口的使用。通过示例代码展示了如何从XML配置文件读取bean信息并创建bean对象。
摘要由CSDN通过智能技术生成

整体代码架构

在这里插入图片描述

1.定义配置类

1.1 查看xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="com.it.dao.impl.UserDaoImpl">
        <property name="username" value="zhangsan"></property>
        <property name="password" value="123456"></property>
    </bean>

    <bean id="userService" class="com.it.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>


    <bean id="student" class="com.it.domain.Student">
        <property name="name" value="wangwu"></property>
    </bean>

</beans>

1.2 PropertyValue

package com.spring.ioc.framework.beans;

/**
 * @version v1.0
 * @ClassName: PropertyValue
 * @Description:
 */

/**
 * @author 
 * @date 2022/9/30 12:46
 * @remark 读取xml中bean标签的property标签的属性
 *
 */
public class PropertyValue {

    private String name;
    private String ref;
    private String value;

    public PropertyValue() {
    }

    public PropertyValue(String name, String ref, String value) {
        this.name = name;
        this.ref = ref;
        this.value = value;
    }

    public String getName() {
        return name;
    }

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

    public String getRef() {
        return ref;
    }

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

    public String getValue() {
        return value;
    }

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

1.3 MutablePropertyValues

package com.spring.ioc.framework.beans;

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

/**
 * @author 
 * @date 2022/10/18 11:38
 * @remark 一个bean标签下有多个property
 */

public class MutablePropertyValues implements Iterable<PropertyValue> {

    /**
     *
     * 定义list集合对象,用来存储PropertyValue对象
     * */
    private final List<PropertyValue> propertyValueList;

    public MutablePropertyValues() {
        this.propertyValueList = new ArrayList<PropertyValue>();
    }

    public MutablePropertyValues(List<PropertyValue> propertyValueList) {
        if(propertyValueList == null) {
            this.propertyValueList = new ArrayList<PropertyValue>();
        } else {
            this.propertyValueList = propertyValueList;
        }
    }

    /**
     *
     * 获取所有的PropertyValue对象,返回以数组的形式
     *
     * */
    public PropertyValue[] getPropertyValues() {
        //将集合转换为数组并返回
        return propertyValueList.toArray(new PropertyValue[0]);
    }

    /**
     *
     * 根据name属性值获取PropertyValue对象
     *
     * */
    public PropertyValue getPropertyValue(String propertyName) {
        //遍历集合对象
        for (PropertyValue propertyValue : propertyValueList) {
            if (propertyValue.getName().equals(propertyName)) {
                return propertyValue;
            }
        }
        return null;
    }

    /**
     *
     * 判断集合是否为空
     *
     * */
    public boolean isEmpty() {
        return propertyValueList.isEmpty();
    }

    /**
     *
     * 添加PropertyValue对象
     *
     * */
    public MutablePropertyValues addPropertyValue(PropertyValue pv) {
        //判断集合中存储的PropertyValue对象是否和传递进行的重复了,如果重复了,进行覆盖
        for (int i = 0; i < propertyValueList.size(); i++) {
            //获取集合中每一个PropertyValue对象
            PropertyValue currentPv = propertyValueList.get(i);
            if(currentPv.getName().equals(pv.getName())) {
                propertyValueList.set(i,pv);
                //目的就是实现链式编程
                return this;
            }
        }
        //目的就是实现链式编程
        this.propertyValueList.add(pv);
        return this;
    }


    /**
     *
     * 判断是否有指定name属性值的对象
     *
     * */
    public boolean contains(String propertyName) {
        return getPropertyValue(propertyName) != null;
    }

    /**
     *
     * 获取迭代器对象
     *
     * */
    public Iterator<PropertyValue> iterator() {
        return propertyValueList.iterator();
    }
}

1.4 BeanDefinition

一个完整的bean配置

package com.spring.ioc.framework.beans;

/**
 * @author 
 * @date 2022/9/30 12:46
 * @remark BeanDefinition类用来封装bean信息的,主要包含id(即bean对象的名称)、
 *         class(需要交由spring管理的类的全类名)及子标签property数据。
 *
 */
public class BeanDefinition {

    private String id;
    private String className;

    private MutablePropertyValues propertyValues;

    public BeanDefinition() {
        propertyValues = new MutablePropertyValues();
    }

    public String getId() {
        return id;
    }

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

    public String getClassName() {
        return className;
    }

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

    public MutablePropertyValues getPropertyValues() {
        return propertyValues;
    }

    public void setPropertyValues(MutablePropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }
}

        //1,创建spring的容器对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        //2,从容器对象中获取userService对象
        UserService userService = applicationContext.getBean("userService", UserService.class);

2. 定义注册表相关类

将全部读取到的BeanDefinition存储起来

2.1 BeanDefinitionRegistry

package com.spring.ioc.framework.beans.factory.support;


import com.spring.ioc.framework.beans.BeanDefinition;

/**
 * @author 
 * @date 2022/9/30 12:46
 * @remark 注册表对象
 *
 */
public interface BeanDefinitionRegistry {

    /**
     * 注册BeanDefinition对象到注册表中
     * */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    /**
     *
     * 从注册表中删除指定名称的BeanDefinition对象
     *
     * */
    void removeBeanDefinition(String beanName) throws Exception;

    /**
     *
     * 根据名称从注册表中获取BeanDefinition对象
     *
     * */
    BeanDefinition getBeanDefinition(String beanName) throws Exception;

    /**
     *
     * 注册表中是否存在BeanDefinition对象
     *
     * */
    boolean containsBeanDefinition(String beanName);

    /**
     *
     * 获取BeanDefinition对象数量
     *
     * */
    int getBeanDefinitionCount();

    /**
     *
     * 获取BeanDefinition对象名称数组
     *
     * */
    String[] getBeanDefinitionNames();
}

2.2 SimpleBeanDefinitionRegistry

package com.spring.ioc.framework.beans.factory.support;



import com.spring.ioc.framework.beans.BeanDefinition;

import java.util.HashMap;
import java.util.Map;


/**
 * @author 
 * @date 2022/9/30 12:46
 * @remark 该类实现了BeanDefinitionRegistry接口,定义了Map集合作为注册表容器。
 *
 */
public class SimpleBeanDefinitionRegistry implements BeanDefinitionRegistry {
    /**
     * 定义一个容器,用来存储BeanDefinition对象
     *
     * **/
    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName,beanDefinition);
    }

    public void removeBeanDefinition(String beanName) throws Exception {
        beanDefinitionMap.remove(beanName);
    }

    public BeanDefinition getBeanDefinition(String beanName) throws Exception {
        return beanDefinitionMap.get(beanName);
    }

    public boolean containsBeanDefinition(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames() {
        return beanDefinitionMap.keySet().toArray(new String[0]);
    }
}

3.定义具体读取配置的类

3.1 BeanDefinitionReader

package com.spring.ioc.framework.beans.factory.support;



/**
 * @author 
 * @date 2022/9/30 12:46
 * @remark 用来解析配置文件的,因为配置文件有xml,yml等多种形式,
 *         具体实现类要继承该接口
 */
public interface BeanDefinitionReader {

    /**
     * 获取注册表对象
     * */
    BeanDefinitionRegistry getRegistry();

    /**
     * 加载配置文件并在注册表中进行注册
     * */
    void loadBeanDefinitions(String configLocation) throws Exception;
}

package com.spring.ioc.framework.beans.factory.xml;


import com.spring.ioc.framework.beans.BeanDefinition;
import com.spring.ioc.framework.beans.MutablePropertyValues;
import com.spring.ioc.framework.beans.PropertyValue;
import com.spring.ioc.framework.beans.factory.support.BeanDefinitionReader;
import com.spring.ioc.framework.beans.factory.support.BeanDefinitionRegistry;
import com.spring.ioc.framework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

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

/**
 * @author
 * @date 2022/9/30 12:46
 * @remark 解析xml配置类
 *
 */
public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    //声明注册表对象
    private final BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader() {

        registry = new SimpleBeanDefinitionRegistry();
    }

    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    public void loadBeanDefinitions(String configLocation) throws Exception {
        //使用dom4j进行xml配置文件的解析
        SAXReader reader = new SAXReader();
        //获取类路径下的配置文件
        InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
        Document document = reader.read(is);
        //根据Document对象获取根标签对象 (beans)
        Element rootElement = document.getRootElement();
        //获取根标签下所有的bean标签对象
        List<Element> beanElements = rootElement.elements("bean");
        //遍历集合
        for (Element beanElement : beanElements) {
            //获取id属性
            String id = beanElement.attributeValue("id");
            //获取class属性
            String className = beanElement.attributeValue("class");

            //将id属性和class属性封装到BeanDefinition对象中
            //1,创建BeanDefinition
            BeanDefinition beanDefinition = new BeanDefinition();
            beanDefinition.setId(id);
            beanDefinition.setClassName(className);

            //创建MutablePropertyValues对象
            MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();

            //获取bean标签下所有的property标签对象
            List<Element> propertyElements = beanElement.elements("property");
            for (Element propertyElement : propertyElements) {
                String name = propertyElement.attributeValue("name");
                String ref = propertyElement.attributeValue("ref");
                String value = propertyElement.attributeValue("value");
                PropertyValue propertyValue = new PropertyValue(name,ref,value);
                mutablePropertyValues.addPropertyValue(propertyValue);
            }
            //将mutablePropertyValues对象封装到BeanDefinition对象中
            beanDefinition.setPropertyValues(mutablePropertyValues);

            //将beanDefinition对象注册到注册表中
            registry.registerBeanDefinition(id,beanDefinition);
        }

    }
}

4.IOC容器类(创建bean操作)

4.1 BeanFactory接口

package com.spring.ioc.framework.beans.factory;

/**
 * @author 
 * @date 2022/10/18 14:05
 * @remark IOC容器父接口
 */
public interface BeanFactory {


    Object getBean(String name) throws Exception;


    <T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}

4.2 ApplicationContext接口,继承BeanFactory

package com.spring.ioc.framework.context;

import com.spring.ioc.framework.beans.factory.BeanFactory;

/**
 * @author 
 * @date 2022/10/18 14:08
 * @remark 该接口的所以的子实现类对bean对象的创建都是非延时的,所以在该接口中定义 `refresh()` 方法,该方法主要完成以下两个功能:
 *         1.加载配置文件。2.根据注册表中的BeanDefinition对象封装的数据进行bean对象的创建。
 */
public interface ApplicationContext extends BeanFactory {

    void refresh() throws IllegalStateException, Exception;

}

4.3 抽象方法 AbstractApplicationContext实现ApplicationContext的refresh()方法

package com.spring.ioc.framework.context.support;

import com.spring.ioc.framework.beans.BeanDefinition;
import com.spring.ioc.framework.beans.factory.support.BeanDefinitionReader;
import com.spring.ioc.framework.beans.factory.support.BeanDefinitionRegistry;
import com.spring.ioc.framework.context.ApplicationContext;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 
 * @date 2022/10/18 14:11
 * @remark
 */
public abstract class AbstractApplicationContext implements ApplicationContext {


    /**
     *
     * 读取配置类接口
     **/
    protected BeanDefinitionReader beanDefinitionReader;
    /**
     *
     * 用来存储bean对象的容器   key存储的是bean的id值,value存储的是bean对象
     **/
    protected Map<String, Object> singletonObjects = new HashMap<String, Object>();

    /**
     *
     * 存储配置文件的路径
     * **/
    protected String configLocation;


    public void refresh() throws IllegalStateException, Exception {
        //加载BeanDefinition
        beanDefinitionReader.loadBeanDefinitions(configLocation);
        //初始化bean
        finishBeanInitialization();
    }

    /**
     *
     * bean的初始化
     * **/
    private void finishBeanInitialization() throws Exception {

        //获取注册表
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();

        String[] beanNames = registry.getBeanDefinitionNames();

        //初始化bean
        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            getBean(beanName);
        }
    }
}

4.4 实现类ClassPathXmlApplicationContext,反射创建bean,继承AbstractApplicationContext,实现最顶层的BeanFactory

package com.spring.ioc.framework.context.support;

import com.spring.ioc.framework.beans.BeanDefinition;
import com.spring.ioc.framework.beans.MutablePropertyValues;
import com.spring.ioc.framework.beans.PropertyValue;
import com.spring.ioc.framework.beans.factory.support.BeanDefinitionRegistry;
import com.spring.ioc.framework.beans.factory.xml.XmlBeanDefinitionReader;
import com.spring.ioc.framework.utils.StringUtils;

import java.lang.reflect.Method;


/**
 * @author 
 * @date 2022/10/18 14:11
 * @remark IOC容器子实现类,
 * 该类主要是加载类路径下的配置文件,并进行bean对象的创建,主要完成以下功能:
 * 在构造方法中,创建BeanDefinitionReader对象。
 * 在构造方法中,调用refresh()方法,用于进行配置文件加载、创建bean对象并存储到容器中。
 * 重写父接口中的getBean()方法,并实现依赖注入操作。
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        //构建解析器对象
        beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {

        }
    }

    //根据bean对象的名称获取bean对象
    public Object getBean(String name) throws Exception {
        //判断对象容器中是否包含指定名称的bean对象,如果包含,直接返回即可,如果不包含,需要自行创建
        Object obj = singletonObjects.get(name);
        if (obj != null) {
            return obj;
        }

        //获取BeanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        //获取bean信息中的className
        String className = beanDefinition.getClassName();
        //通过反射创建对象
        Class<?> clazz = Class.forName(className);
        Object beanObj = clazz.newInstance();

        //进行依赖注入操作
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            //获取name属性值
            String propertyName = propertyValue.getName();
            //获取value属性
            String value = propertyValue.getValue();
            //获取ref属性
            String ref = propertyValue.getRef();
            if (ref != null && !"".equals(ref)) {
                //获取依赖的bean对象
                Object bean = getBean(ref);
                //拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                //获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (methodName.equals(method.getName())) {
                        //执行该setter方法
                        method.invoke(beanObj, bean);
                    }
                }
            }

            if (value != null && !"".equals(value)) {
                //拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                //获取method对象
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }
        }

        //在返回beanObj对象之前,将该对象存储到map容器中
        singletonObjects.put(name, beanObj);
        return beanObj;
    }

    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if (bean == null) {
            return null;
        }
        return clazz.cast(bean);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值