zl程序教程

您现在的位置是:首页 >  后端

当前栏目

spring-framework源码第3弹------Spring IOC 容器的简单实现(学习tiny-spring)

Spring源码容器学习 实现 简单 Framework ------
2023-09-27 14:19:46 时间

声明:本代码来源于tiny-spring ,感谢原作者的源码
修改后的代码tiny-spring-copy

前言

学习Spring源码之前先学习下微缩版的Spring 框架—–tiny-spring 框架。闲话少说,先从IoC 容器开始。

IoC 的实现流程

  1. 读取配置文件,获取资源输入流
  2. 解析Bean,生成Bean的实例,
  3. 根据依赖注入Bean的实例

读取配置文件

Resource 接口,标识一个外部资源,通过getInputStream()获取资源的输入流

public interface Resource {

    InputStream getInputStream() throws IOException;
}

UrlResource 实现Resource接口

public class UrlResource implements Resource {

    private final URL url;

    public UrlResource(URL url) {
        this.url = url;
    }

    @Override
    public InputStream getInputStream() throws IOException{
        URLConnection urlConnection = url.openConnection();
        urlConnection.connect();
        return urlConnection.getInputStream();
    }
}

ResourceLoader 接口,加载资源,返回UrlResource 对象

public interface ResourceLoader {
    /**
     * @param location
     * @return
     */
    public Resource getResource(String location);
}

UrlResourceLoader类实现ResourceLoader接口

public class UrlResourceLoader implements ResourceLoader {

    @Override
    public Resource getResource(String location){
        URL resource = this.getClass().getClassLoader().getResource(location);
        return new UrlResource(resource);
    }
}

解析配置文件,获取Bean的定义

  1. BeanDefinition 实体类,用于存放Bean的定义,包括Bean的内容和属性
public class BeanDefinition {

    /**
     * 
     */
    private Object bean;

    /**
     * Bean的类型
     */
    private Class beanClass;

    /**
     * Bean的名称
     */
    private String beanClassName;

    /**
     * 属性类,内部封装了一个List<PropertyValue>
     */
    private PropertyValues propertyValues = new PropertyValues();

    get和set方法省略

}
  1. BeanDefinitionReader 解析 BeanDefinition接口,通过loadBeanDefinitions(String) 从一个地址加载类的定义
public interface BeanDefinitionReader {

    /**
     * 从配置中读取BeanDefinition
     * @param location
     * @throws Exception
     */
    void loadBeanDefinitions(String location) throws Exception;
}
  1. AbstractBeanDefinitionReader
    实现BeanDefinitionReader接口的抽象类,未具体实现loadBeanDefinitions(String),主要是规范了BeanDefinitionReader的基本结构,
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
    //用于保存String - beanDefinition 的键值对
    private Map<String,BeanDefinition> registry;
    //用于保存类加载器
    private UrlResourceLoader resourceLoader;

    protected AbstractBeanDefinitionReader(UrlResourceLoader resourceLoader) {
        this.registry = new HashMap<String, BeanDefinition>();
        this.resourceLoader = resourceLoader;
    }

    public Map<String, BeanDefinition> getRegistry() {
        return registry;
    }

    public UrlResourceLoader getResourceLoader() {
        return resourceLoader;
    }
}
  1. XmlBeanDefinitionReader类,具体实现BeanDefinitionReader接口,从配置文件中获取Bean的定义
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(UrlResourceLoader resourceLoader) {
        super(resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(String location) throws Exception {
        InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
        doLoadBeanDefinitions(inputStream);
    }

    protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        Document doc = docBuilder.parse(inputStream);
        // 解析bean
        registerBeanDefinitions(doc);
        inputStream.close();
    }

    /**
     * 解析Bean
     * @param doc
     */
    public void registerBeanDefinitions(Document doc) {
        Element root = doc.getDocumentElement();

        parseBeanDefinitions(root);
    }

    /**
     * 解析Bean
     * @param root
     */
    protected void parseBeanDefinitions(Element root) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                processBeanDefinition(ele);
            }
        }
    }


    /**
     * 解析Bean中的id和class,以及其他属性
     * @param ele
     */
    protected void processBeanDefinition(Element ele) {
        String name = ele.getAttribute("id");
        String className = ele.getAttribute("class");
        BeanDefinition beanDefinition = new BeanDefinition();
        //保存属性
        processProperty(ele, beanDefinition);
        //保存类全限定名
        beanDefinition.setBeanClassName(className);
        //将获得的Bean的定义保存到map中
        getRegistry().put(name, beanDefinition);
    }

    /**
     * 解析Bean中的property属性
     * @param ele
     * @param beanDefinition
     */
    private void processProperty(Element ele, BeanDefinition beanDefinition) {
        NodeList propertyNode = ele.getElementsByTagName("property");
        for (int i = 0; i < propertyNode.getLength(); i++) {
            Node node = propertyNode.item(i);
            if (node instanceof Element) {
                Element propertyEle = (Element) node;
                String name = propertyEle.getAttribute("name");
                String value = propertyEle.getAttribute("value");
                if (value != null && value.length() > 0) {
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                } else {
                    String ref = propertyEle.getAttribute("ref");
                    if (ref == null || ref.length() == 0) {
                        throw new IllegalArgumentException("Configuration problem: <property> element for property '"
                                + name + "' must specify a ref or value");
                    }
                    BeanReference beanReference = new BeanReference(ref);
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
                }
            }
        }
    }
}

注册生成Bean的实例 以及使用该实例

BeanFactory类,标识一个IoC容器,通过getBean(String)来获取Bean的实例。

public interface BeanFactory {

    Object getBean(String name) throws Exception;

}

AbstractBeanFactory类,BeanFactory的一种抽象实现,规范了IoC容器的基本结构,但是把生成Bean的具体方式留给了子类来实现。

public abstract class AbstractBeanFactory implements BeanFactory {

    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    private final List<String> beanDefinitionNames = new ArrayList<String>();

    private List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

    @Override
    public Object getBean(String name) throws Exception {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new IllegalArgumentException("No bean named " + name + " is defined");
        }
        Object bean = beanDefinition.getBean();
        //如果bean存在,则返回。否则调用doCreateBean方法装配一个Bean
        if (bean == null) {
            bean = doCreateBean(beanDefinition);
            bean = initializeBean(bean, name);
            beanDefinition.setBean(bean);
        }
        return bean;
    }

    /**
     * 对Bean做初始化
     * @param bean
     * @param name
     * @return
     * @throws Exception
     */
    protected Object initializeBean(Object bean, String name) throws Exception {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessBeforeInitialization(bean, name);
        }

        // TODO:call initialize method
        for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, name);
        }
        return bean;
    }

    protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
        return beanDefinition.getBeanClass().newInstance();
    }

    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        beanDefinitionMap.put(name, beanDefinition);
        beanDefinitionNames.add(name);
    }

    public void preInstantiateSingletons() throws Exception {
        for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
            String beanName = (String) it.next();
            getBean(beanName);
        }
    }

    /**
     * 创建一个Bean的实例
     * @param beanDefinition
     * @return
     * @throws Exception
     */
    protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
        Object bean = createBeanInstance(beanDefinition);
        beanDefinition.setBean(bean);
        applyPropertyValues(bean, beanDefinition);
        return bean;
    }

    protected void applyPropertyValues(Object bean, BeanDefinition beanDefinition) throws Exception {

    }

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) throws Exception {
        this.beanPostProcessors.add(beanPostProcessor);
    }

    public List getBeansForType(Class type) throws Exception {
        List beans = new ArrayList<Object>();
        for (String beanDefinitionName : beanDefinitionNames) {
            if (type.isAssignableFrom(beanDefinitionMap.get(beanDefinitionName).getBeanClass())) {
                beans.add(getBean(beanDefinitionName));
            }
        }
        return beans;
    }

}

AutowireCapableBeanFactory 可以实现自动装配的 BeanFactory。在这个工厂中,实现了doCreateBean方法,该方法分为三步:1. 通过BeanDefinition中保存的类信息实例化一个对象;2.将对象保存在BeanDefinition中,以备下次获取;3. 为其装配属性。在装配属性时,通过BeanDefinition中维护的PropertyValues集合类,把String-Value键值对注入到Bean的属性中去。如果Value的类型是BeanReference,则说明其是一个引用(对应于XML中的ref),通过getBean对其进行获取,然后注入到属性中。

public class AutowireCapableBeanFactory extends AbstractBeanFactory {


    /**
     * 将读取到的property值设置到Bean中
     * @param bean
     * @param mbd
     * @throws Exception
     */
    protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
            Object value = propertyValue.getValue();
            if (value instanceof BeanReference) {
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getName());
            }

            try {
                Method declaredMethod = bean.getClass().getDeclaredMethod(
                        "set" + propertyValue.getName().substring(0, 1).toUpperCase()
                                + propertyValue.getName().substring(1), value.getClass());
                declaredMethod.setAccessible(true);
                //反射方式设值
                declaredMethod.invoke(bean, value);
            } catch (NoSuchMethodException e) {
                Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
                declaredField.setAccessible(true);
                declaredField.set(bean, value);
            }
        }
    }
}

ApplicationContext 接口以及其实现类,主要是对Resource,BeanFactory,BeanDefinition进行功能封装,解决根据地址获取IoC容器并使用的问题。
AbstractApplicationContext 类,ApplicationContext 的抽象实现,内部包含一个 BeanFactory

public abstract class AbstractApplicationContext implements ApplicationContext {
    protected AbstractBeanFactory beanFactory;

    public AbstractApplicationContext(AbstractBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public void refresh() throws Exception {
        loadBeanDefinitions(beanFactory);
        registerBeanPostProcessors(beanFactory);
        onRefresh();
    }

    protected abstract void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception;

    protected void registerBeanPostProcessors(AbstractBeanFactory beanFactory) throws Exception {
        List beanPostProcessors = beanFactory.getBeansForType(BeanPostProcessor.class);
        for (Object beanPostProcessor : beanPostProcessors) {
            beanFactory.addBeanPostProcessor((BeanPostProcessor) beanPostProcessor);
        }
    }

    protected void onRefresh() throws Exception{
        beanFactory.preInstantiateSingletons();
    }

    @Override
    public Object getBean(String name) throws Exception {
        return beanFactory.getBean(name);
    }
}

ClassPathXmlApplicationContext 类,从类路径加载资源的具体实现类

public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    private String configLocation;

    public ClassPathXmlApplicationContext(String configLocation) throws Exception {
        this(configLocation, new AutowireCapableBeanFactory());
    }

    public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
        super(beanFactory);
        this.configLocation = configLocation;
        refresh();
    }

    @Override
    protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new UrlResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }
    }

tiny-spring 的ApplicaitonContext使用流程是这样的:

  1. ApplicaitonContext完成了类定义的读取和加载,并注册到BeanFactory中去。
  2. ApplicaitonContextBeanFactory中寻找BeanPostProcessor,注册到BeanFactory维护的BeanPostProcessor列表中去。
  3. ApplicaitonContext以单例的模式,通过主动调用getBean实例化、注入属性、然后初始化BeanFactory中所有的Bean。由于所有的BeanPostProcessor都已经在第2步中完成实例化了,因此接下来实例化的是普通Bean,因此普通Bean的初始化过程可以正常执行。
  4. 调用getBean时,委托给BeanFactory,此时只是简单的返回每个Bean单例,因为所有的Bean实例在第三步都已经生成了。

参考

https://www.zybuluo.com/dugu9sword/note/382745#%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84