zoukankan      html  css  js  c++  java
  • 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的原理,才能对框架本身理解的更加透彻。

  • 相关阅读:
    题解 CF171G 【Mysterious numbers
    题解 P1157 【组合的输出】
    题解 P3955 【图书管理员】
    题解 P2036 【Perket】
    题解 CF837A 【Text Volume】
    题解 CF791A 【Bear and Big Brother】
    题解 CF747A 【Display Size】
    题解 P1332 【血色先锋队】
    题解 P2660 【zzc 种田】
    题解 P4470 【[BJWC2018]售票】
  • 原文地址:https://www.cnblogs.com/zeng-xian-hui/p/11301176.html
Copyright © 2011-2022 走看看