手写Spring之IOC

 

本篇博客参考github开源项目https://github.com/code4craft/tiny-spring,从零开始手写简易版Spring框架,并且给予更详细的注释和个人见解。

1.构建BeanFactory,创建bean的实例

/**
 * @author Jalen.Deng
 * @description bean工厂-最基本的容器
 * @date 2020/11/23 20:36
 **/
public class BeanFactory {
    //创建beanDefinitionMap来存储bean的实例
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    public Object getBean(String name) {
        return beanDefinitionMap.get(name).getBean();
    }

    /**
     * 注册bean到beanDefinitionMap中
     * @param name
     * @param beanDefinition
     */
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(name, beanDefinition);
    }
}
/**
 * @author Jalen.Deng
 * @description bean定义,可以理解为层层包装后的bean
 * @date 2020/11/23 20:46
 **/
public class BeanDefinition {
    private Object bean;

    public BeanDefinition(Object bean) {
        this.bean = bean;
    }

    public Object getBean() {
        return bean;
    }
}
/**
 * @author Jalen.Deng
 * @description 
 * @date 2020/11/23 20:51
 **/
public class BeanFactoryTest {
    public static void main(String[] args) {
        //初始化beanFactory
        BeanFactory beanFactory = new BeanFactory();
        //创建bean实例
        BeanDefinition helloWorldServiceBean = new BeanDefinition(new HelloWorldService());
        //注册bean实例到beanFactory
        beanFactory.registerBeanDefinition("helloWorldService",helloWorldServiceBean);
        //通过getBean()方法获取bean实例
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        //调用hello方法
        helloWorldService.helloWorld();
    }
}

对比Spring中的实现 DefaultListableBeanFactory 中 registerBeanDefinition 和getBean方法

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
		Assert.notNull(requiredType, "Required type must not be null");
		Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
		if (resolved == null) {
			throw new NoSuchBeanDefinitionException(requiredType);
		}
		return (T) resolved;
	}
/**
 *  NoSuchBeanDefinitionException是一个很常见的报错,缺少bean的定义,简单来说,就是
 * Spring在启动的时候会去实例化所有bean对象,结果没有在context上找到该实例。如果你使用注解,
 * 那么就是impl没有用@Service进行注册,如果你使用xml配置,就是没有使用<bean />进行配置
 */

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
//篇幅有限,删减一些校验判断代码

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
             //这个配置很关键,允许bean定义覆盖,一般报BeanDefinitionOverrideException
             //就是没有开启这个配置
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
            //核心就是这段代码
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
	
	}

 

2.构建AbstractBeanFactory,将bean加入工厂进行管理。

package com.dl.spring.factory;

import com.dl.spring.BeanDefinition;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Jalen.Deng
 * @description 定义BeanFactory工厂接口
 * @date 2020/11/23 20:36
 **/
public interface BeanFactory {

    /**
     * 通过beanName获取bean实例
     * @param name
     * @return
     */
     Object getBean(String name);

    /**
     * 注册bean到beanDefinitionMap中
     * @param name
     * @param beanDefinition
     */
     void registerBeanDefinition(String name, BeanDefinition beanDefinition);
}

 

package com.dl.spring;

/**
 * @author Jalen.Deng
 * @description bean定义,可以理解为层层包装后的bean。
 * @date 2020/11/23 20:46
 **/
public class BeanDefinition {
    private Object bean;

    private Class beanClass;

    private String beanClassName;

    public BeanDefinition() {
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Object getBean() {
        return bean;
    }
}
/**
 * @author Jalen.Deng
 * @description 抽象bean工厂
 * @date 2020/11/23 21:31
 **/
public abstract class AbstractBeanFactory implements BeanFactory {
    /**
     *创建beanDefinitionMap来存储bean的实例
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    @Override
    public Object getBean(String name) {
        return beanDefinitionMap.get(name).getBean();
    }
    /**
     * 注册bean到beanDefinitionMap中
     * @param name
     * @param beanDefinition
     */
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
    }
    /**
     * 初始化bean
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition);
}
package com.dl.spring.factory;

import com.dl.spring.BeanDefinition;

/**
 * @author Jalen.Deng
 * @description 自动装配,通过反射创建bean对象
 * @date 2020/11/23 21:35
 **/
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    protected Object doCreateBean(BeanDefinition beanDefinition) {
        Object bean = null;
        try {
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

 

对比Spring实现:AbstractAutowireCapableBeanFactory#createBean#doCreateBean。可以自己debug跟踪

 

3.为bean注入属性(重要)

public abstract class AbstractBeanFactory implements BeanFactory {
    /**
     *创建beanDefinitionMap来存储bean的实例
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

    @Override
    public Object getBean(String name) {
        return beanDefinitionMap.get(name).getBean();
    }
    /**
     * 注册bean到beanDefinitionMap中
     * @param name
     * @param beanDefinition
     */
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        Object bean = doCreateBean(beanDefinition);
        beanDefinition.setBean(bean);
        beanDefinitionMap.put(name, beanDefinition);
    }
    /**
     * 初始化bean
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;
}
/**
 * @author Jalen.Deng
 * @description 自动装配工厂,通过反射new对象
 * @date 2020/11/23 21:35
 **/
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
        Object bean = createBeanInstance(beanDefinition);
        applyPropertyValues(bean, beanDefinition);
        return bean;
    }

    protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
        for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
            Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
            declaredField.setAccessible(true);
            declaredField.set(bean, propertyValue.getValue());
        }

    }

    protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
        return beanDefinition.getBeanClass().newInstance();
    }
}
/**
 * @author Jalen.Deng
 * @description bean的内容及元数据,保存在BeanFactory中,包装bean的实体
 * @date 2020/11/23 20:46
 **/
public class BeanDefinition {
    private Object bean;

    private Class beanClass;

    private String beanClassName;

    private PropertyValues propertyValues;

    public BeanDefinition() {
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Object getBean() {
        return bean;
    }

    public PropertyValues getPropertyValues() {
        return propertyValues;
    }

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

/**
 * @author Jalen.Deng
 * @description 为bean注入属性
 * @date 2020/11/24 9:09
 **/
public class PropertyValue {

    private final String name;

    private final Object value;

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

    public String getName() {
        return name;
    }

    public Object getValue() {
        return value;
    }
}
/**
 * @author Jalen.Deng
 * @description 包装一个对象所有的PropertyValue。
 * 为什么封装而不是直接用List?因为可以封装一些操作。
 * @date 2020/11/24 9:08
 **/
public class PropertyValues {
    private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();

    public PropertyValues() {
    }

    public void addPropertyValue(PropertyValue pv) {
        //TODO:这里可以对于重复propertyName进行判断,直接用list没法做到
        this.propertyValueList.add(pv);
    }

    public List<PropertyValue> getPropertyValues() {
        return this.propertyValueList;
    }
}
/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/23 21:50
 **/
public class BeanFactoryTest {
    public static void main(String[] args) throws Exception {
        //初始化bean工厂
        BeanFactory beanFactory = new AutowireCapableBeanFactory();
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setBeanClassName("com.dl.spring.HelloWorldService");
        PropertyValues propertyValues = new PropertyValues();
        //为bean注入属性,name属性在HelloWorldService定义好
        propertyValues.addPropertyValue(new PropertyValue("name","jalen"));
        beanDefinition.setPropertyValues(propertyValues);
        //生成bean
        beanFactory.registerBeanDefinition("helloWorldService", beanDefinition);
        //获取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}

对比Spring实现:AbstractAutowireCapableBeanFactory#createBean#doCreateBean#populateBean#applyPropertyValues。可以自己debug跟踪

	populateBean.java

if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

//通过名称或者类型去注入属性

以上就是Spring的核心代码,底层使用的是反射机制。初始化bean要写这么多代码实在是费劲,我们来优化一下。

4.读取xml配置来初始化bean

 

package com.dl.spring.io;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author Jalen.Deng
 * @description Resource是spring内部定位资源的接口。
 * @date 2020/11/24 14:34
 **/
public interface Resource {
    InputStream getInputStream() throws IOException;
}
package com.dl.spring.io;

import java.net.URL;

/**
 * @author Jalen.Deng
 * @description 资源加载器
 * @date 2020/11/24 14:35
 **/
public class ResourceLoader {
    public Resource getResource(String location){
        URL resource = this.getClass().getClassLoader().getResource(location);
        return new UrlResource(resource);
    }
}
package com.dl.spring.io;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

/**
 * @author Jalen.Deng
 * @description url资源类
 * @date 2020/11/24 14:35
 **/
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();
    }
}

核心类xmlBeanDefinitionReader

package com.dl.spring.xml;

import com.dl.spring.AbstractBeanDefinitionReader;
import com.dl.spring.BeanDefinition;
import com.dl.spring.PropertyValue;
import com.dl.spring.io.Resource;
import com.dl.spring.io.ResourceLoader;
import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;

/**
 * @author Jalen.Deng
 * @description xml解析bean定义
 * @date 2020/11/24 14:32
 **/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

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

    @Override
    public void loadBeanDefinitions(String location) throws Exception {
        //使用io输入流获取xml中所有bean信息
        InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
        //加载解析xml
        doLoadBeanDefinitions(inputStream);
    }

    /**
     * @param inputStream
     * @throws Exception
     */
    protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {
        //学过xml相关知识我们可以知道,要获取xml内容首先要构建dom树对象
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        //Document是个接口,代表整个html或者xml文档,是文档树的根
        Document doc = documentBuilder.parse(inputStream);
        registerBeanDefinitions(doc);
        inputStream.close();

    }

    protected void registerBeanDefinitions(Document doc) {
        //getDocumentElement允许直接访问文档元素的子节点
        Element root = doc.getDocumentElement();
        //解析bean定义核心方法
        parseBeanDefinitions(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);
            }
        }
    }

    protected void processBeanDefinition(Element ele) {
        /**
         *<bean name="helloWorldService" class="com.dl.spring.HelloWorldService">
         *      <property name="name" value="Hello World!"></property>
         * </bean>
         */
        String name = ele.getAttribute("name");
        String className = ele.getAttribute("class");
        BeanDefinition beanDefinition = new BeanDefinition();
        processProperty(ele,beanDefinition);
        beanDefinition.setBeanClassName(className);
        getRegistry().put(name, beanDefinition);
    }

    private void processProperty(Element ele, BeanDefinition beanDefinition) {
        //其实就是解析 <property name="name" value="Hello World!"></property>
        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");
                beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name,value));
            }
        }
    }
}

 

package com.dl.spring;

import com.dl.spring.io.ResourceLoader;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/24 14:43
 **/
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader{
    //存储bean定义信息的map
    private Map<String,BeanDefinition> registry;

    private ResourceLoader resourceLoader;

    public AbstractBeanDefinitionReader(ResourceLoader resourceLoader) {
        this.registry = new ConcurrentHashMap<String, BeanDefinition>();
        this.resourceLoader = resourceLoader;
    }

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

    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }
}
package com.dl.spring;

/**
 * @author Jalen.Deng
 * @description bean的内容及元数据,保存在BeanFactory中,包装bean的实体
 * @date 2020/11/23 20:46
 **/
public class BeanDefinition {
    private Object bean;

    private Class beanClass;

    private String beanClassName;

    private PropertyValues propertyValues = new PropertyValues();;

    public BeanDefinition() {
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanClassName() {
        return beanClassName;
    }

    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
        try {
            this.beanClass = Class.forName(beanClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Object getBean() {
        return bean;
    }

    public PropertyValues getPropertyValues() {
        return propertyValues;
    }

    public void setPropertyValues(PropertyValues propertyValues) {
        this.propertyValues = propertyValues;
    }
}
package com.dl.spring;

/**
 * @author Jalen.Deng
 * @description 从配置中读取BeanDefinitionReader
 * @date 2020/11/24 14:43
 **/
public interface BeanDefinitionReader {

    void loadBeanDefinitions(String location) throws Exception;
}

其他类与前面步骤保持不变,最后测试

package com.dl.spring.xml;

import com.dl.spring.BeanDefinition;
import com.dl.spring.io.ResourceLoader;
import org.junit.Test;

import java.util.Map;

/**
 * @author Jalen.Deng
 * @description 测试读取配置文件
 * @date 2020/11/24 14:42
 **/
public class XmlBeanDefinitionReaderTest {

    public static void main(String[] args) throws Exception{
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
        Map<String, BeanDefinition> registry = xmlBeanDefinitionReader.getRegistry();
        System.out.println(registry.get("helloWorldService"));
    }
    @Test
    public void test() throws Exception{
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
        Map<String, BeanDefinition> registry = xmlBeanDefinitionReader.getRegistry();
        System.out.println(registry.get("helloWorldService"));
    }
}
package com.dl.spring;

import com.dl.spring.factory.AutowireCapableBeanFactory;
import com.dl.spring.factory.BeanFactory;
import com.dl.spring.io.ResourceLoader;
import com.dl.spring.xml.XmlBeanDefinitionReader;

import java.util.Map;

/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/23 21:50
 **/
public class BeanFactoryTest {
    public static void main(String[] args) throws Exception {
        // 1.读取配置
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

        // 2.初始化BeanFactory并注册bean
        BeanFactory beanFactory = new AutowireCapableBeanFactory();
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }

        // 3.获取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}
package com.dl.spring.io;

import org.junit.Assert;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author Jalen.Deng
 * @description 使用resource读取配置文件
 * @date 2020/11/24 14:42
 **/
public class ResourceLoaderTest {

	@Test
	public void test() throws IOException {
		ResourceLoader resourceLoader = new ResourceLoader();
        Resource resource = resourceLoader.getResource("spring.xml");
        InputStream inputStream = resource.getInputStream();
        Assert.assertNotNull(inputStream);
    }
}

resources文件夹下添加spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean name="helloWorldService" class="com.dl.spring.HelloWorldService">
        <property name="name" value="Hello World!"></property>
    </bean>

</beans>

loadBeanDefinitions的流程图

对应Spring实现:XmlBeanDefinitionReader#loadBeanDefinitions#doLoadBeanDefinitions

流程很复杂,因此不贴代码

5.为bean注入bean

优化BeanFactory类 registerBeanDefinition只做bean的注册

/**
 * @author Jalen.Deng
 * @description 抽象bean工厂
 * @date 2020/11/23 21:31
 **/
public abstract class AbstractBeanFactory implements BeanFactory {
    /**
     *创建beanDefinitionMap来存储bean的实例
     */
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

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

    @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();
        if (bean == null) {
            bean = doCreateBean(beanDefinition);
        }
        return bean;
    }
    /**
     * 注册bean到beanDefinitionMap中
     * @param name
     * @param beanDefinition
     */
    @Override
    public void registerBeanDefinition(String name, BeanDefinition beanDefinition) throws Exception {
        beanDefinitionMap.put(name, beanDefinition);
        beanDefinitionNames.add(name);
    }

    //初始化bean单例
    public void preInstantiateSingletons() throws Exception {
        for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
            String beanName = (String) it.next();
            getBean(beanName);
        }
    }

    /**
     * 初始化bean
     * @param beanDefinition
     * @return
     */
    protected abstract Object doCreateBean(BeanDefinition beanDefinition) throws Exception;
}
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
    @Override
    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 mbd) throws Exception {
        for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
            Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
            declaredField.setAccessible(true);
            Object value = propertyValue.getValue();
            //BeanReference为helloService,outputService
            if(value instanceof BeanReference){
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanReference.getName());
            }
            declaredField.set(bean,value);
        }

    }

    protected Object createBeanInstance(BeanDefinition beanDefinition) throws Exception {
        return beanDefinition.getBeanClass().newInstance();
    }
}
package com.dl.spring.xml;

/**
 * @author Jalen.Deng
 * @description xml解析bean定义
 * @date 2020/11/24 14:32
 **/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
   /**
  *...省略之前相同的代码
  **/


    private void processProperty(Element ele, BeanDefinition beanDefinition) {
        //其实就是解析 <property name="name" value="Hello World!"></property>
        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");
                /**
                 * <bean name="helloWorldService" class="com.dl.spring.HelloWorldService">
                 *         <property name="outputService" ref="outputService"></property>
                 *     </bean>
                 */
                if (value != null && value.length() > 0) {
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                } else {
                    String ref = propertyEle.getAttribute("ref");
                    //ref为helloWorldService,outputService,可以看出,加载顺序从上到下。
                    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));
                }
            }
        }
    }
}
package com.dl.spring;

/**
 * @author Jalen.Deng
 * @description bean引用,用于处理bean之间相互依赖
 * @date 2020/11/25 9:01
 **/
public class BeanReference {
    private String name;

    private Object bean;

    public BeanReference(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }
}
package com.dl.spring;

import com.dl.spring.factory.AbstractBeanFactory;
import com.dl.spring.factory.AutowireCapableBeanFactory;
import com.dl.spring.factory.BeanFactory;
import com.dl.spring.io.ResourceLoader;
import com.dl.spring.xml.XmlBeanDefinitionReader;
import org.junit.Test;

import java.util.Map;

/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/23 21:50
 **/
public class BeanFactoryTest {
    @Test
    public void testLazy() throws Exception {
        // 1.读取配置
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

        // 2.初始化BeanFactory并注册bean
        AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory();
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }

        // 3.获取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.getOutputService().output("output");
        helloWorldService.helloWorld();
    }

    @Test
    public void testPreInstantiate() throws Exception {
        // 1.读取配置
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");

        // 2.初始化BeanFactory并注册bean
        AbstractBeanFactory beanFactory = new AutowireCapableBeanFactory();
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }

        // 3.初始化bean
        beanFactory.preInstantiateSingletons();

        // 4.获取bean
        HelloWorldService helloWorldService = (HelloWorldService) beanFactory.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!--为outputService注入helloWorldService -->
    <bean name="outputService" class="com.dl.spring.OutputService">
        <property name="helloWorldService" ref="helloWorldService"></property>
    </bean>
    <!--为helloWorldService注入outputService -->
    <bean name="helloWorldService" class="com.dl.spring.HelloWorldService">
        <property name="name" value="Hello World!"></property>
        <property name="outputService" ref="outputService"></property>
    </bean>

</beans>

对比Spring中的实现:DefaultListableBeanFactory#preInstantiateSingletons

这里补充一点:Spring是如何解决bean之间循环依赖的问题呢?

参考 https://www.jianshu.com/p/8bb67ca11831

https://blog.csdn.net/f641385712/article/details/92801300

这里我就说一点,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为上层bean的属性(A依赖B,B就是上层,也就是类A里面注入了B对象)。这也就是说,当我们使用构造器进行注入,A构造方法里new B对象,Spring是无法解决的,需要自己手动改代码以及换其他方式进行注入。

那么面试怎么回答呢?

①Spring是使用三级缓存解决循环依赖的,所谓三级缓存也就是三个map,单例对象缓存(存储可以直接使用的bean),半成品单例对象缓存(bean完成了实例化,但是没有注入属性),单例对象工厂缓存(存放 bean 工厂对象)。

②首先先去单例对象缓存取,取到了直接返回,没有的话就去半成品单例对象缓存取,取到了也直接返回,没有取到就去单例对象工厂缓存里,

开启allowEarlyReference=true这个配置通过singletonFactory.getObject()方法创建ObjectFactory类型的对象,然后“移动”到半成品单例对象缓存里,最后委托给doCreateBean去完成bean的初始化。

 

6使用ApplicationContext,在refresh()方法中初始化bean

package com.dl.spring.context;


import com.dl.spring.factory.AbstractBeanFactory;
import com.dl.spring.factory.BeanFactory;

/**
 * @author Jalen.Deng
 * @description 创建上下文对象接口
 * @date 2020/11/24 14:43
 **/
public interface ApplicationContext extends BeanFactory {

}
import com.dl.spring.factory.AbstractBeanFactory;
/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/25 10:13
 **/
public abstract class AbstractApplicationContext implements ApplicationContext {

    protected AbstractBeanFactory beanFactory;

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

    public void refresh() throws Exception{
    }

    @Override
    public Object getBean(String name) throws Exception {
        return beanFactory.getBean(name);
    }
}
package com.dl.spring.context;

import com.dl.spring.BeanDefinition;
import com.dl.spring.factory.AbstractBeanFactory;
import com.dl.spring.factory.AutowireCapableBeanFactory;
import com.dl.spring.io.ResourceLoader;
import com.dl.spring.xml.XmlBeanDefinitionReader;

import java.util.Map;

/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/25 10:24
 **/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    private String configLocation;

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

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

    /**
     * 使用refresh方法来注册bean
     * @throws Exception
     */
    @Override
    public void refresh() throws Exception {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
        xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
            beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
        }
    }
}
package com.dl.spring.factory;

import com.dl.spring.BeanDefinition;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Jalen.Deng
 * @description 定义BeanFactory工厂接口
 * @date 2020/11/23 20:36
 **/
public interface BeanFactory {

    /**
     * 通过beanName获取bean实例
     * @param name
     * @return
     */
     Object getBean(String name) throws Exception;

}
package com.dl.spring.context;

import com.dl.spring.HelloWorldService;
import org.junit.Test;

/**
 * @author Jalen.Deng
 * @description
 * @date 2020/11/23 21:50
 **/
public class ApplicationContextTest {

    @Test
    public void test() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
        helloWorldService.helloWorld();
    }
}

对比Spring中的实现:AbstractApplicationContext.refresh方法,非常核心且复杂的方法。

总结

参考

https://www.zybuluo.com/dugu9sword/note/382745#ioc-%E5%AE%B9%E5%99%A8%E7%9A%84%E5%AE%9E%E7%8E%B0

https://github.com/DLoveru/spring-custom

https://github.com/code4craft/tiny-spring

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值