SpringIOC源码分析(基于源码思想手写个人SpringIOC容器)

什么是 IOC/DI?

1.IOC:控制反转,将 bean的对象交给 spring容器来管理。

2.DI:依赖注入,解决对象之间的依赖关系。

springIOC结构体系

(1)BeanFactory:定义了 IOC容器的基本规范--父接口

   (2)ListableBeanFactory:表示这些bean是可列表的。--子接口1

(3)HierarchicalBeanFactory:表示这些bean是有继承关系的。--子接口2

(4)AutowireCapableBeanFactory:定义bean的自动装配规则。--子接口3

(1)最基本的IOC容器接口 BeanFactory

         在BeanFactory里面只对IOC容器的基本行为做了定义。

public interface BeanFactory {    
        
     //如果需要得到工厂本身,需要转义           
     String FACTORY_BEAN_PREFIX = "&"; 
        
     //根据bean的名字,获取在IOC容器中得到bean实例    
     Object getBean(String name) throws BeansException;    
   
    //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。    
     Object getBean(String name, Class requiredType) throws BeansException;    
    
    //提供对bean的检索,看看是否在IOC容器有这个名字的bean    
     boolean containsBean(String name);    
    
    //根据bean名字得到bean实例,并同时判断这个bean是不是单例    
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean实例的Class类型    
    Class getType(String name) throws NoSuchBeanDefinitionException;    
    
    //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
   String[] getAliases(String name);    
    
 }

(2)BeanDefinition接口

              封装xml,解析springbean文件

AbstractRefreshableApplicationContext抽象类的 refreshBeanFactory()这个方法

protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();//创建IOC容器
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);//载入loadBeanDefinitions
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

先调用本类里面的 loadBeanDefinitions(beanFactory)

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {  实现
/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

先调用本类里面的 loadBeanDefinitions(beanDefinitionReader)

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

委托给 reader.loadBeanDefinitions(configLocation)

           根据传进来的配置文件路径,循环读取配置文件。

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int counter = 0;
		for (String location : locations) {
			counter += loadBeanDefinitions(location);
		}
		return counter;
	}

进入到 loadBeanDefinitions(location)

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}

		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try {
			InputStream inputStream = encodedResource.getResource().getInputStream();//获取IO
			try {
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());//这个方法从流中读取
			}
			finally {
				inputStream.close();
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}

进入到doLoadBeanDefinitions(inputSource,encodedResource.getResource())  Resource IO封装

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
			int validationMode = getValidationModeForResource(resource);
			Document doc = this.documentLoader.loadDocument(
					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
			return registerBeanDefinitions(doc, resource); //解析XML
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}
进入到 loadDocument(
         inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
//使用标准的JAXP将载入的Bean定义资源转换成document对象  
   public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,  
           ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {  
       //创建文件解析器工厂  
       DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);  
       if (logger.isDebugEnabled()) {  
           logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");  
       }  
       //创建文档解析器  
       DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);  
       //解析Spring的Bean定义资源  
       return builder.parse(inputSource);  
   }  
   protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)  
           throws ParserConfigurationException {  
       //创建文档解析工厂  
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
       factory.setNamespaceAware(namespaceAware);  
       //设置解析XML的校验  
       if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {  
           factory.setValidating(true);  
           if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {  
               factory.setNamespaceAware(true);  
               try {  
                   factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);  
               }  
               catch (IllegalArgumentException ex) {  
                   ParserConfigurationException pcex = new ParserConfigurationException(  
                           "Unable to validate using XSD: Your JAXP provider [" + factory +  
                           "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +  
                           "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");  
                   pcex.initCause(ex);  
                   throw pcex;  
               }  
           }  
       }  
       return factory;  
   }

进入到registerBeanDefinitions (doc, resource); //解析XML ,读取 bean

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// Read document based on new BeanDefinitionDocumentReader SPI.
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

进入到 documentReader.registerBeanDefinitions(doc, createReaderContext(resource))进行注册

           我的天 终于拿到根路径 root,开始解析,唯一操作parseBeanDefinitions(root,delegate)

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;

		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();

		BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

		preProcessXml(root);
		parseBeanDefinitions(root, delegate);
		postProcessXml(root);
	}

进入到 parseBeanDefinitions(root,delegate)

        两种解析节点方式:1.parseDefaultElement(ele,delegate) --默认解析

                                         2.delegate.parseCustomElement(root)--自定义解析

-----遍历节点
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(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;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate); //默认解析
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

进入到默认解析parseDefaultElement(ele,delegate)

         三种解析方式写的非常规范,我们走解析bean方式

---判断解析类	
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);//import类型
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);//别名方式
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);//bean解析方式
		}
	}

进入到 processBeanDefinition(ele, delegate)bean 解析方式

           bean id名称根据bdHolder而来

//解析Bean定义资源Document对象的普通元素  
   protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
       // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类  
       //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
       if (bdHolder != null) {  
           bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
           try {  
              //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口            
                  BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
           }  
           catch (BeanDefinitionStoreException ex) {  
               getReaderContext().error("Failed to register bean definition with name '" +  
                       bdHolder.getBeanName() + "'", ele, ex);  
           }  
           //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件  
           getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
       }  
   }

调用registerBeanDefinitions(bdHolder, getReaderContext().getRegistry())

            启动Spring IoC容器对Bean定义的解析过程

//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构  
   public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
       //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析  
       BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
       //获得容器中注册的Bean数量  
       int countBefore = getRegistry().getBeanDefinitionCount();  
       //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,//具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成  
       documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  
       //统计解析的Bean数量  
       return getRegistry().getBeanDefinitionCount() - countBefore;  
   }  
   //创建BeanDefinitionDocumentReader对象,解析Document对象  
   protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {  
       return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));  
      }

Bean的解析方式:

          进入到 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  

使用反射初始化类

public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);

			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

			parseConstructorArgElements(ele, bd);
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

进入到AbstractBeanDefinition bd = createBeanDefinition(className, parent);

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
			throws ClassNotFoundException {

		return BeanDefinitionReaderUtils.createBeanDefinition(
				parentName, className, this.readerContext.getBeanClassLoader());
	}

进入到BeanDefinitionReaderUtils.createBeanDefinition

         终于反射机制初始化 bean了

public static AbstractBeanDefinition createBeanDefinition(
			String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {

		GenericBeanDefinition bd = new GenericBeanDefinition();
		bd.setParentName(parentName);
		if (className != null) {
			if (classLoader != null) {
				bd.setBeanClass(ClassUtils.forName(className, classLoader));//使用java反射机制初始化
			}
			else {
				bd.setBeanClassName(className);
			}
		}
		return bd;
	}

手写springIoc容器

package com.xuyuedu.entity;

public class UserEntity {
	private String userId;
	private String userName;

	 public UserEntity(){
		 System.out.println("无参构造函数....");
	 }
	
	public String getUserId() {

		return userId;
	}

	public void setUserId(String userId) {

		this.userId = userId;
	}

	public String getUserName() {

		return userName;
	}

	public void setUserName(String userName) {

		this.userName = userName;
	}

	@Override
	public String toString() {
		return "UserEntity [userId=" + userId + ", userName=" + userName + "]";
	}

}
package com.xuyuedu.test;

import java.lang.reflect.Field;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.xuyuedu.entity.UserEntity;

public class ClassPathXmlApplicationContext {
	private static String PATH;
	private static String ID;
	private static String CLASS;
	private static String NAME;
	private static String VALUE;

	public void init() {
		ID = "id";
		CLASS = "class";
		NAME = "name";
		VALUE = "value";
	}

	public ClassPathXmlApplicationContext(String path) {
		init();
		// 获取spring读取文件名称
		this.PATH = path;
	}

	public Object getBean(String beanId) throws DocumentException, ClassNotFoundException, InstantiationException,
			IllegalAccessException, NoSuchFieldException, SecurityException {
		// 1、解析xml
		if (StringUtils.isEmpty(beanId)) {
			return null;
		}
		SAXReader saxReader = new SAXReader();
		Document read = saxReader.read(this.getClass().getClassLoader().getResource(PATH));
		//获取根节点【beans】
		Element rootElement = read.getRootElement();
		//获得根节点下的所有子节点【bean】
		List<Element> elements = rootElement.elements();
		//遍历子节点
		for (Element element : elements) {
			//找到Id
			String id = element.attributeValue(ID);
			if (!beanId.equals(id)) {
				// 结束本次循环
				continue;
			}
			// 2、使用beanid查找对应xml节点,获取class节点属性
			// 从配置文件中获取bean【class】
			String attClass = element.attributeValue(CLASS);
			// 3、使用java的反射机制初始化类
			Class<?> forName = Class.forName(attClass);
			//反射调用有参函数
			Object newInstance = forName.newInstance();
			// 4、获取属性【properties】
			List<Element> sonEle = element.elements();
			//遍历属性下的name,value
			for (Element el : sonEle) {
				// 获取配置文件属性名称
				String attField = el.attributeValue(NAME);
				String attFieldValue = el.attributeValue(VALUE);
				//获得私有属性
				Field declaredField = forName.getDeclaredField(attField);
				//暴力反射获取私有属性
				declaredField.setAccessible(true);
				//给有参构造函数赋值【value】
				declaredField.set(newInstance, attFieldValue);
			}
			return newInstance;
		}
		return null;

	}

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException,
			IllegalAccessException, NoSuchFieldException, SecurityException, DocumentException {
		ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserEntity user = (UserEntity) app.getBean("user2");
		System.out.println(user.toString());
	}

}

测试结果:

无参构造函数....
UserEntity [userId=0003, userName=腾讯课堂]

猜你喜欢

转载自blog.csdn.net/qq_38357267/article/details/81082832