Spring ioc容器的实现

1. 说明

本文将通过源码分析spring ioc容器的实现。

参考书籍《Spring 技术内幕 第二版》

2. 开始

  • 依赖翻转

    首先要明白Spring容器的思想依赖翻转,什么是依赖翻转呢?在面向对象编程中经常会出现一个对象内部引用了另一个对象,这种关系就是对象的依赖关系,通过这种依赖关系,对象之间就可以合作完成各种不同的功能。但是他也有缺陷,如果不同的类相互引用势必会造成代码高度耦合,如何解决这个问题呢?下面是我自己个人的理解。

    通常我们经常会写如下代码

    class A{
        B b=new B();
    }
    

    这是很典型的一种引用关系,但是假如有一天,B这个类进行了修改,我们使用了一个B1去继承B,然后重写了方法,这个时候我们要对代码进行修改。

    class A{
        B b=new B1();
    }
    

    但是这种做法并不好,原因有两个,我们需要将所有出现B b=new B()的地方进行更改,显然这样做的成本很高,另外根据面向对象的基本原则中的开闭原则,应该对扩展开放面对修改闭合,也就是说我们可以新增代码,但是不要去修改代码。可是这里不修改似乎不行。

    那我们换一种思路,下面是伪代码。

    class A{
        B b;//这里有一个b成员,但是没有初始化,请根据配置文件通过setB方法为b赋予值
        void setB(B b){
            this.b=b;
        }
    }
    

    我们站在A类的角度,以前的代码是由A去维护B的引用,而现在确不是了,A类只提供了一个引用,但是这个引用的实际类型是什么并不知道,它需要我们在实例化的时候去设置。

    那么当我们需要用到B1的时候,我们岂不是只要更改一下配置文件就可以完成代码的更新,这样既符合开闭原则,而且A类不与具体的对象相关联,而是与接口相关,这对我们维护代码提供了遍历。

    总结一下前面的分析,我们以前的做法是类主动维护依赖关系,而现在却把维护这种关系的责任交给了类的外部,这种思想便是依赖翻转。

  • Spring IoC

    任何理念思想都应该有产品对象,Spring的核心IoC容器就是这样一个产品,Spring框架中所有的对象都交给IoC容器管理,包括对象之间的依赖关系,如下面代码所示。

  class A{
    @AutoWired
      B b;
  }

通过注解就可以将B的实例注入进对象中,从而完成了对象的依赖关系管理。

那么对于一个IoC容器而言,需要实现什么样的功能呢?

最重要的两个功能应该是

  • 如何获取被管理的对象

  • 如何设置依赖关系

  • BeanFactory和BeanDefinition

解释一下两个最重要的类。

在Spring中,我们通常把由Spring容器管理的对象称为Bean。BeanFactory是Spring中最基本和最核心的接口,顾名思义可以知道这个接口用来管理和创建对象,因此这个接口定义了IoC容器的基本功能,也就是说BeanFactory实际上代表IoC容器,凡是实现了BeanFactory接口的实现类都代表IoC容器,如我们经常通过下面代码获取容器

    ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");

上面的ApplicationContext就是我们所说的容器,而他也是BeanFactory的实现类类。

再看看BeanFactory的源码

public interface BeanFactory {

    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String name) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    
    boolean containsBean(String name);

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    String[] getAliases(String name);

}

BeanFactory最多的方法就是getBean,这符合一个容器的特征。什么是容器呢?现实生活中,容器就是用来装东西的,IoC容器就是用来装bean的,既然里面装着bean,那么我们自然可以把它取出来。

BeanDefinition是什么呢?

IoC容器需要管理对象,其实有两种方法,第一种实现思路是直接管理我们写好的类,如果要获取对象从类中new一个出来就可以了,显然这种方式不太灵活,并且每次都要去判断该对象依赖的对象是什么。另一种实现思路是容器本身管理一种类型,所有用户的类都要转换成容器规定的这种类型,这样的话IoC容器具有什么样的功能取决于容器管理的类型而不是用户写的类。Spring IoC管理的就是容器实现的数据类型,这种类型就是BeanDefinition。

我们通常通过下面的xml文件管理bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="testService" class="TestService" scope="singleton"></bean>
</beans>

对于Spring Ioc来说,会把配置文件中的所有bean标签转化为一个BeanDefinition,然后添加到Spring IoC容器中管理,也就是BeanFactory的实现类。

看一下BeanDefinition的源码

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
    int ROLE_APPLICATION = 0;
    
    int ROLE_SUPPORT = 1;
    
    int ROLE_INFRASTRUCTURE = 2;

    void setParentName(@Nullable String parentName);
    
    @Nullable
    String getParentName();

    void setBeanClassName(@Nullable String beanClassName);
    
    @Nullable
    String getBeanClassName();
    
    void setScope(@Nullable String scope);
    
    @Nullable
    String getScope();

    void setLazyInit(boolean lazyInit);

    boolean isLazyInit();

    void setDependsOn(@Nullable String... dependsOn);
    
    @Nullable
    String[] getDependsOn();
    
    void setAutowireCandidate(boolean autowireCandidate);

    boolean isAutowireCandidate();
    
    void setPrimary(boolean primary);
    
    boolean isPrimary();
    
    void setFactoryBeanName(@Nullable String factoryBeanName);

    @Nullable
    String getFactoryBeanName();

    void setFactoryMethodName(@Nullable String factoryMethodName);
    
    @Nullable
    String getFactoryMethodName();

    ConstructorArgumentValues getConstructorArgumentValues();

    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }
    
    MutablePropertyValues getPropertyValues();
    
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }
    
    void setInitMethodName(@Nullable String initMethodName);
    
    @Nullable
    String getInitMethodName();
    
    void setDestroyMethodName(@Nullable String destroyMethodName);
    
    @Nullable
    String getDestroyMethodName();
    
    void setRole(int role);
    
    int getRole();
    
    void setDescription(@Nullable String description);
    
    @Nullable
    String getDescription();
    
    boolean isSingleton();
    
    boolean isPrototype();
    
    boolean isAbstract();
    
    @Nullable
    String getResourceDescription();
    
    @Nullable
    org.springframework.beans.factory.config.BeanDefinition getOriginatingBeanDefinition();

}

可以看到BeanDefinition有很多属性去描述一个bean,比如这个bean属于哪个类,init方法和destroy方法是什么,是否是懒加载,依赖的对象有哪些。

目前我们分析了是谁管理对象,管理的元素是什么,下一个问题是ben的信息放在哪里,从我们使用的角度来看,我们通常可以通过下面的代码获取一个bean

TestService testService1=context.getBean(TestService.class);
TestService testService2= (TestService) context.getBean("textService");

通过我们的编程经验,如果要求查找的效率最高,内部应该维护的是HashMap。我们跟踪一下代码找到这个数据结构出来。

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

上面的代码是由我们通过跟踪getBean方法发现的,我们的目标是一个单例实例,最终发现其保存在一个ConcurrentHashMap中,由此可见我们的猜想是对的,之所以使用ConcurrentHashMap是为了线程安全问题而考虑的。

目前我们知道了bean是如何描述的,bean是由哪个类管理的,存放bean的具体数据结构是什么。但是距离实现一个IoC容器还面临着不少问题,如:

  • 我们定义的bean是转换成BeanDefinition的。
  • IoC容器什么时候将我们的bean的配置文件转化为map这种数据结构的。
  • 如何通过一个BeanDefinition获取到我们需要的bean对象

我们至少要解决上面几个问题才能构建出自己的IoC容器处理,下面我们继续分析。

  • refresh方法

    public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// 为refresh过程做准备
    			prepareRefresh();
    
    			//告诉子类刷新内部bean工厂,完成该步骤,bean就会进入到容器内部
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			//准备bean工厂在此上下文中使用做准备
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// 允许在上下文子类中对bean工厂进行后处理。
    				postProcessBeanFactory(beanFactory);
    
    				// 调用作为bean注册进上下文的处理器
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// 注册拦截bean创建的bean处理器。
    				registerBeanPostProcessors(beanFactory);
    
    				// 初始化此上下文的消息源
    				initMessageSource();
    
    				// 初始化此上下文的事件多播器。
    				initApplicationEventMulticaster();
    
    				// 在特定的上下文子类中初始化其他特殊bean。
    				onRefresh();
    
    				// 检查监听器bean并注册它们。
    				registerListeners();
    
    				// 实例化所有剩余(非延迟初始化)单例。
    				finishBeanFactoryInitialization(beanFactory);
    
    				// 最后一步:发布相应的事件。
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
    
    				// 摧毁已经创建的单例以避免悬空资源。
    				destroyBeans();
    
    				// 重置 'active' 标记.
    				cancelRefresh(ex);
    
    				//向调用者传播异常
    				throw ex;
    			}
    
    			finally {
    				// 重置Spring核心中的常见内省缓存, 因为我们不再需要单例bean的元数据
    				resetCommonCaches();
    			}
    		}
    	}
    

    上面refresh方法的注释是根据源码注释翻译过来的,可以看出refresh方法与容器初始化密切相关。

    IoC容器的初始化的关键在于BeanFactory的获取,通过对代码

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();的跟踪发现如下方法:

    	@Override
    	protected final void refreshBeanFactory() throws BeansException {
            //如果存在BeanFactory就销毁
    		if (hasBeanFactory()) {
    			destroyBeans();
    			closeBeanFactory();
    		}
    		try {
                //创建BeanFactory
    			DefaultListableBeanFactory beanFactory = createBeanFactory();
    			beanFactory.setSerializationId(getId());
    			customizeBeanFactory(beanFactory);
    			//加载BeanDefinition
                loadBeanDefinitions(beanFactory);
    			synchronized (this.beanFactoryMonitor) {
    				this.beanFactory = beanFactory;
    			}
    		}
    		catch (IOException ex) {
    			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    		}
    	}
    
    

    这个方法做了两件事,创建BeanFactory,加载BeanDefinition。

    容器的初始化首先应该创建容器,我们继续跟踪BeanFactory的创建。

    protected DefaultListableBeanFactory createBeanFactory() {
    		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }
    

    可以发现是直接返回来一个DefaultListableBeanFactory;此时获得的BeanFactory是空的,里面什么信息都没有,需要loadBeanDefinitions加载。

    @Override
    	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    		//为传入的BeanFactory参数创建一个XmlBeanDefinitionReader
    		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
    		// 使用此上下文的资源加载环境配置bean定义读取器。
    		beanDefinitionReader.setEnvironment(this.getEnvironment());
    		beanDefinitionReader.setResourceLoader(this);
    		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
    		//允许子类提供reader的自定义初始化,然后继续实际加载bean定义。
    		initBeanDefinitionReader(beanDefinitionReader);
            //加载BeanDefinition
    		loadBeanDefinitions(beanDefinitionReader);
    	}
    

    从该方法可以看出,BeanDefinition的加载与BeanDefinitionReader关系非常大。

    	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
            //获取resource
    		Resource[] configResources = getConfigResources();
    		if (configResources != null) {
    			reader.loadBeanDefinitions(configResources);
    		}
            //获取配置文件的位置,这一步实际上拿到了我们spring.xml的路径信息
    		String[] configLocations = getConfigLocations();
    		if (configLocations != null) {
                //通过reader的loadBeanDefinitions方法,参数为配置信息的位置加载beanDefinition
    			reader.loadBeanDefinitions(configLocations);
    		}
    	}
    

    到了这一步,IoC容器的初始化过程已经非常明显了,现在留给我们的问题只有两个,配置文件是如何获取的,如何加载的,这些问题与getConfigLocations方法和readerloadBeanDefinitions方法有关。

  • 资源定位

    bean的配置信息我们一般写在配置文件中,容器管理bean的自然要找到配置信息。通过下面这行代码的分析

    ApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
    

    配置文件是写在构造方法参数中的,并且ClassPathXmlApplicationContext意味着从ClassPath加载该文件。

    public ClassPathXmlApplicationContext(
    			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    			throws BeansException {
    
    		super(parent);
        	//设置配置文件的位置
    		setConfigLocations(configLocations);
    		if (refresh) {
    			refresh();
    		}
    	}
    
    public void setConfigLocations(@Nullable String... locations) {
    	if (locations != null) {
    		Assert.noNullElements(locations, "Config locations must not be null");
    		this.configLocations = new String[locations.length];
    		for (int i = 0; i < locations.length; i++) {
    			this.configLocations[i] = resolvePath(locations[i]).trim();
    		}
    	}
    	else {
    		this.configLocations = null;
    	}
    }
    

    通过构造方法,location信息已经保存在configLocations了,然后回到上一节的末尾方法;

    protected String[] getConfigLocations() {
    		return (this.configLocations != null ? this.configLocations :getDefaultConfigLocations());
    }
    

    可以看到是直接返回的,如果我们没有传入配置文件路径,那么他会返回一个默认的位置(这个默认的位置其实是null);

    现在已经拿到了配置文件的路径,但是本节开始说过一个问题ClassPathXmlApplicationContext就是从ClassPath下加载该文件,这里我们只有文件路径信息,但是IoC容器如何直到从哪里加载该信息呢?

    继续跟踪代码

    	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
            //获取一个ResourceLoader
    		ResourceLoader resourceLoader = getResourceLoader();
    		if (resourceLoader == null) {
    			throw new BeanDefinitionStoreException(
    					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
    		}
    
    		if (resourceLoader instanceof ResourcePatternResolver) {
    			// Resource pattern matching available.
    			try {
                    //通过ResourceLoader的getResources方法,以配置文件位置信息获取resource
    				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                    //以resource为参数加载BeanDefinition
    				int count = loadBeanDefinitions(resources);
    				if (actualResources != null) {
    					Collections.addAll(actualResources, resources);
    				}
    				if (logger.isTraceEnabled()) {
    					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
    				}
    				return count;
    			}
    			catch (IOException ex) {
    				throw new BeanDefinitionStoreException(
    						"Could not resolve bean definition resource pattern [" + location + "]", ex);
    			}
    		}
    		else {
    			// Can only load single resources by absolute URL.
    			Resource resource = resourceLoader.getResource(location);
    			int count = loadBeanDefinitions(resource);
    			if (actualResources != null) {
    				actualResources.add(resource);
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
    			}
    			return count;
    		}
    	}
    

    Resource对象就是配置文件的封装,获取到了resource就相当于准确定位到了配置文件。

  • 载入和解析

    获取到了Resource对象就可以完成BeanDefinition的载入和解析了,这个过程将配置文件的信息加载进入IoC容器,然后通过这些信息获取到具体的BeanDefinition实例。

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    		Assert.notNull(encodedResource, "EncodedResource must not be null");
    		if (logger.isTraceEnabled()) {
    			logger.trace("Loading XML bean definitions from " + encodedResource);
    		}
    
    		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    		if (currentResources == null) {
    			currentResources = new HashSet<>(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();
    			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())语句

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    			throws BeanDefinitionStoreException {
    
    		try {
                //将配置文件解析成Document对象
    			Document doc = doLoadDocument(inputSource, resource);
                //-> 进入该方法
    			int count = registerBeanDefinitions(doc, resource);
    			if (logger.isDebugEnabled()) {
    				logger.debug("Loaded " + count + " bean definitions from " + resource);
    			}
    			return count;
    		}
    		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);
    		}
    	}
    
    

    进入int count = registerBeanDefinitions(doc, resource);语句

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //获取一个BeanDefinitionDocumentReader对象
    		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    		int countBefore = getRegistry().getBeanDefinitionCount();
        //调用documentReader的方法 -> 进入该方法
    		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    		return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    

    继续documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    		this.readerContext = readerContext;
        //->
    		doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    

    继续doRegisterBeanDefinitions(doc.getDocumentElement());

    	protected void doRegisterBeanDefinitions(Element root) {
            //BeanDefinitionParserDelegate真正完成解析工作
    		BeanDefinitionParserDelegate parent = this.delegate;
    		this.delegate = createDelegate(getReaderContext(), root, parent);
    
    		if (this.delegate.isDefaultNamespace(root)) {
    			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    			if (StringUtils.hasText(profileSpec)) {
    				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    					if (logger.isDebugEnabled()) {
    						logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
    								"] not matching: " + getReaderContext().getResource());
    					}
    					return;
    				}
    			}
    		}
    
    		preProcessXml(root);
            //解析BeanDefinition ->
    		parseBeanDefinitions(root, this.delegate);
    		postProcessXml(root);
    
    		this.delegate = parent;
    	}
    

    继续parseBeanDefinitions(root, this.delegate);

    	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);

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    			importBeanDefinitionResource(ele);
    		}
    		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    			processAliasRegistration(ele);
    		}
    		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                //如果ele元素是一个Bean的话,调用下面的方法
    			processBeanDefinition(ele, delegate);
    		}
    		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    			// recurse
    			doRegisterBeanDefinitions(ele);
    		}
    	}
    

    继续processBeanDefinition(ele, delegate);

    	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            //通过delegate的parseBeanDefinitionElement方法获取BeanDefinitionHolder实例
    		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    		if (bdHolder != null) {
    			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    			try {
    				// Register the final decorated instance.
    				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    			}
    			catch (BeanDefinitionStoreException ex) {
    				getReaderContext().error("Failed to register bean definition with name '" +
    						bdHolder.getBeanName() + "'", ele, ex);
    			}
    			// Send registration event.
    			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    		}
    	}
    

    继续delegate.parseBeanDefinitionElement(ele);

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        	//获取bean的id
    		String id = ele.getAttribute(ID_ATTRIBUTE);
        	//获取bean的名称
    		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
    		List<String> aliases = new ArrayList<>();
    		if (StringUtils.hasLength(nameAttr)) {
    			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    			aliases.addAll(Arrays.asList(nameArr));
    		}
    		
    		String beanName = id;
    		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    			beanName = aliases.remove(0);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No XML 'id' specified - using '" + beanName +
    						"' as bean name and " + aliases + " as aliases");
    			}
    		}
    
    		if (containingBean == null) {
    			checkNameUniqueness(beanName, aliases, ele);
    		}
    
    		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    		if (beanDefinition != null) {
    			if (!StringUtils.hasText(beanName)) {
    				try {
    					if (containingBean != null) {
    						beanName = BeanDefinitionReaderUtils.generateBeanName(
    								beanDefinition, this.readerContext.getRegistry(), true);
    					}
    					else {
    						beanName = this.readerContext.generateBeanName(beanDefinition);
    						// Register an alias for the plain bean class name, if still possible,
    						// if the generator returned the class name plus a suffix.
    						// This is expected for Spring 1.2/2.0 backwards compatibility.
    						String beanClassName = beanDefinition.getBeanClassName();
    						if (beanClassName != null &&
    								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
    								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    							aliases.add(beanClassName);
    						}
    					}
    					if (logger.isTraceEnabled()) {
    						logger.trace("Neither XML 'id' nor 'name' specified - " +
    								"using generated bean name [" + beanName + "]");
    					}
    				}
    				catch (Exception ex) {
    					error(ex.getMessage(), ele);
    					return null;
    				}
    			}
    			String[] aliasesArray = StringUtils.toStringArray(aliases);
                //将BeanDefinition封装成一个BeanDefinitionHolder对象返回
    			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    		}
    
    		return null;
    	}
    

    上面的方法结束,就获取到了一个BeanDefinition

    根据返回语句return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);可知到这一步配置文件中的bean已经转化为一个BeanDefinition了

  • 注册

    BeanDefinition已经获取到了,现在要做的试将BeanDefinition保存在IoC容器中,这一步就发送在BeanDefinitionHolder获取之后。

    public static void registerBeanDefinition(
    			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    			throws BeanDefinitionStoreException {
    
    		// 使用初始的名称注册
    		String beanName = definitionHolder.getBeanName();
        	//-> 进入方法
    		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    		// 注册别名
    		String[] aliases = definitionHolder.getAliases();
    		if (aliases != null) {
    			for (String alias : aliases) {
    				registry.registerAlias(beanName, alias);
    			}
    		}
    	}
    
    

    继续registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());,这个方法将beanName和BeanDefinition作为参数传入,可以预料到最终的注册就发送在这个方法中。

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException {
    		//断言校验beanName和beanDefinition是否有问题
    		Assert.hasText(beanName, "Bean name must not be empty");
    		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    		//判断BeanDefinition是不是AbstractBeanDefinition类型的
    		if (beanDefinition instanceof AbstractBeanDefinition) {
    			try {
    				((AbstractBeanDefinition) beanDefinition).validate();
    			}
    			catch (BeanDefinitionValidationException ex) {
    				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    						"Validation of bean definition failed", ex);
    			}
    		}
    		//判断已经存在同名的BeanDefinition
    		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    		if (existingDefinition != null) {
    			if (!isAllowBeanDefinitionOverriding()) {
    				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    			}
    			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
    				if (logger.isInfoEnabled()) {
    					logger.info("Overriding user-defined bean definition for bean '" + beanName +
    							"' with a framework-generated bean definition: replacing [" +
    							existingDefinition + "] with [" + beanDefinition + "]");
    				}
    			}
    			else if (!beanDefinition.equals(existingDefinition)) {
    				if (logger.isDebugEnabled()) {
    					logger.debug("Overriding bean definition for bean '" + beanName +
    							"' with a different definition: replacing [" + existingDefinition +
    							"] with [" + beanDefinition + "]");
    				}
    			}
    			else {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Overriding bean definition for bean '" + beanName +
    							"' with an equivalent definition: replacing [" + existingDefinition +
    							"] with [" + beanDefinition + "]");
    				}
    			}
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    		}
    		else {
    			if (hasBeanCreationStarted()) {
    				synchronized (this.beanDefinitionMap) {
                        //将beanName作为key,BeanDefinition作为value保存在HashMap中
    					this.beanDefinitionMap.put(beanName, beanDefinition);
    					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    					updatedDefinitions.addAll(this.beanDefinitionNames);
    					updatedDefinitions.add(beanName);
    					this.beanDefinitionNames = updatedDefinitions;
    					removeManualSingletonName(beanName);
    				}
    			}
    			else {
    				// Still in startup registration phase
    				this.beanDefinitionMap.put(beanName, beanDefinition);
    				this.beanDefinitionNames.add(beanName);
    				removeManualSingletonName(beanName);
    			}
    			this.frozenBeanDefinitionNames = null;
    		}
    
    		if (existingDefinition != null || containsSingleton(beanName)) {
    			resetBeanDefinition(beanName);
    		}
    	}
    

    this.beanDefinitionMap.put(beanName, beanDefinition);将BeanDefinition保存到了文章最开始猜想的HashMap中,此时BeanDefinition已经保存到了IoC容器中。

  • 依赖注入

    依赖注入发生在第一次获取Bean的时候,注意完成了上一步,IoC容器中存放的并不是bean对象而是BeanDefinition,从BeanDefinition信息获取bean对象就是依赖注入的过程。

    通过beanFactory的getBean方法获取,这里我们以beanName作为参数。

    public Object getBean(String name) throws BeansException {
       return doGetBean(name, null, null, false);
    }
    

    进入doGetBean方法

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
    			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
    		final String beanName = transformedBeanName(name);
    		Object bean;
    
    		// 单例对象会放到缓存中,所以先去缓存中获取bean
    		Object sharedInstance = getSingleton(beanName);
    		if (sharedInstance != null && args == null) {
    			if (logger.isTraceEnabled()) {
    				if (isSingletonCurrentlyInCreation(beanName)) {
    					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    							"' that is not fully initialized yet - a consequence of a circular reference");
    				}
    				else {
    					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    				}
    			}
                //从factoryBean对象中获取bean
    			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    		}
    		else {
    			// Fail if we're already creating this bean instance:
    			// We're assumably within a circular reference.
    			if (isPrototypeCurrentlyInCreation(beanName)) {
    				throw new BeanCurrentlyInCreationException(beanName);
    			}
    
    			// 检查对应的BeanDefinition是否存在
    			BeanFactory parentBeanFactory = getParentBeanFactory();
    			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    				// 如果当前BeanFactory中不能存在,并且有父BeanFactory则检查父BeanFactory
    				String nameToLookup = originalBeanName(name);
    				if (parentBeanFactory instanceof AbstractBeanFactory) {
    					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
    							nameToLookup, requiredType, args, typeCheckOnly);
    				}
    				else if (args != null) {
    					// Delegation to parent with explicit args.
    					return (T) parentBeanFactory.getBean(nameToLookup, args);
    				}
    				else if (requiredType != null) {
    					// No args -> delegate to standard getBean method.
    					return parentBeanFactory.getBean(nameToLookup, requiredType);
    				}
    				else {
    					return (T) parentBeanFactory.getBean(nameToLookup);
    				}
    			}
    
    			if (!typeCheckOnly) {
    				markBeanAsCreated(beanName);
    			}
    
    			try {
    				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    				checkMergedBeanDefinition(mbd, beanName, args);
    
    				// 保证当前bean依赖的bean的初始化.
    				String[] dependsOn = mbd.getDependsOn();
    				if (dependsOn != null) {
    					for (String dep : dependsOn) {
    						if (isDependent(beanName, dep)) {
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    						}
    						registerDependentBean(dep, beanName);
    						try {
    							getBean(dep);
    						}
    						catch (NoSuchBeanDefinitionException ex) {
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
    						}
    					}
    				}
    
    				// 创建bean实例
                    //如果当前bean是一个单例
    				if (mbd.isSingleton()) {
    					sharedInstance = getSingleton(beanName, () -> {
    						try {
    							return createBean(beanName, mbd, args);
    						}
    						catch (BeansException ex) {
    							destroySingleton(beanName);
    							throw ex;
    						}
    					});
    					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    				}
    
    				else if (mbd.isPrototype()) {
    					// 如果是prototype类型 -> 创建一个新的实例.
    					Object prototypeInstance = null;
    					try {
    						beforePrototypeCreation(beanName);
    						prototypeInstance = createBean(beanName, mbd, args);
    					}
    					finally {
    						afterPrototypeCreation(beanName);
    					}
    					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    				}
    
    				else {
    					String scopeName = mbd.getScope();
    					final Scope scope = this.scopes.get(scopeName);
    					if (scope == null) {
    						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
    					}
    					try {
    						Object scopedInstance = scope.get(beanName, () -> {
    							beforePrototypeCreation(beanName);
    							try {
    								return createBean(beanName, mbd, args);
    							}
    							finally {
    								afterPrototypeCreation(beanName);
    							}
    						});
    						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    					}
    					catch (IllegalStateException ex) {
    						throw new BeanCreationException(beanName,
    								"Scope '" + scopeName + "' is not active for the current thread; consider " +
    								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
    								ex);
    					}
    				}
    			}
    			catch (BeansException ex) {
    				cleanupAfterBeanCreationFailure(beanName);
    				throw ex;
    			}
    		}
    
    		// Check if required type matches the type of the actual bean instance.
    		if (requiredType != null && !requiredType.isInstance(bean)) {
    			try {
    				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
    				if (convertedBean == null) {
    					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    				}
    				return convertedBean;
    			}
    			catch (TypeMismatchException ex) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Failed to convert bean '" + name + "' to required type '" +
    							ClassUtils.getQualifiedName(requiredType) + "'", ex);
    				}
    				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    			}
    		}
    		return (T) bean;
    	}
    
    

3. 总结

spring IoC容器是spring框架的核心,spring IoC管理着spring框架的bean,是spring mvc等其他框架的基石,只有充分理解IoC的原理,才能对框架本身理解的更加透彻。

posted @ 2019-08-05 09:36  _zeng  阅读(181)  评论(0编辑  收藏  举报