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的原理,才能对框架本身理解的更加透彻。

  • 相关阅读:
    【原创】驱动加载之OpenService
    【原创】驱动加载之CreateService
    【原创】驱动加载之OpenSCManager
    【原创】如何由结构体成员的地址逆算出结构体首地址
    【原创+整理】简述何为调用约定,函数导出名以及extern C
    【整理】WDK 和 DDK异同
    java IO流
    java StringBuffer与StringBuilder
    java集合——进度1
    javaweb——总结
  • 原文地址:https://www.cnblogs.com/zeng-xian-hui/p/11301176.html
Copyright © 2011-2022 走看看