Spring IOC源码分析

本文深入探讨 Spring IOC 的源码结构,从 BeanFactory 到 BeanDefinition 的解析过程,详细阐述 Spring 如何实现依赖注入,以及初始化过程中的关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/shi1122/article/category/580946

 

spring IOC源码分析(1)

  1.何谓Spring IOC

        何谓Spring IOC?书上谓之“依赖注入”,那何谓“依赖注入”?

        作为一个Java程序猿,应该遇到过这样的问题,当你在代码中需要使用某个类提供的功能时,你首先需要new一个对象,给它传递必要的参数,然后才能使用它提供的功能,最后释放对象占用的内存,当然了这个在Java不需要你自己去干了。这也就是说你需要自己去管理变量的整个生命周期,这在大型项目中是很糟糕的。现在好了,有了Spring IOC,这些事情都不需要你去做,你只需要告诉Spring你需要的变量实例,配置其对应关系,Spring就可以讲你依赖的实例注入到你的变量中。

        举个现实的例子,在以前大家找对象都是自己去找,自己去处的,现在不一样了,很多人都通过相亲了,这就有了相亲机构,其实这里相亲机构就是一个Spring IOC容器,你想要找对象,然后你就去找相亲机构,在它那里注个册,告诉它你的要求,比如说高矮胖瘦等等,这个时候,相亲机构就从已经在它那注册了的所有女生中(注:这个时候,你跟那些女生都是相亲机构管理的bean对象)找到符合你要求的女生,最后给到你,让你们自己去折腾了……,这也就是所谓的“依赖注入”,也就是Spring IOC的精髓所在。

 

2 Spring IOC体系结构

 

Bean工厂

         SpringBean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:


        其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。

 

Bean的表示

         SpringIOC容器管理了我们定义的各种Bean对象及其相互的关系,Bean对象在Spring实现中是以BeanDefinition来描述的,其继承体系如下:


        Bean 的解析过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:



        

        

       2. 最基本的IOC容器接口:

       

[java]  view plain copy
  1. 1.  public interface BeanFactory {    
  2. 2.      
  3. 3.  //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,    
  4. 4.  //如果需要得到工厂本身,需要转义           
  5. 5.      String FACTORY_BEAN_PREFIX = "&";    
  6. 6.      
  7. 7.      
  8. 8.  //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。    
  9. 9.      Object getBean(String name) throws BeansException;    
  10. 10.     
  11. 11//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。    
  12. 12.     Object getBean(String name, Class requiredType) throws BeansException;    
  13. 13.     
  14. 14//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean    
  15. 15.     boolean containsBean(String name);    
  16. 16.     
  17. 17.     //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件    
  18. 18.     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
  19. 19.     
  20. 20.     //这里对得到bean实例的Class类型    
  21. 21.     Class getType(String name) throws NoSuchBeanDefinitionException;    
  22. 22.     
  23. 23.     //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
  24. 24.     String[] getAliases(String name);    
  25. 25.     
  26. 26. }   

         在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是如何定义怎样加载的。正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。

         而要知道工厂是如何产生对象的,我们需要看具体的IOC容器实现,spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。


3.    IoC容器的初始化

       

        IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。我们以ApplicationContext为例讲解,ApplicationContext系列容器也许是我们最熟悉的,因为web项目中使用的XmlWebApplicationContext就属于这个继承体系,还有ClasspathXmlApplicationContext等,其继承体系如下图所示:



         ApplicationContext允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。


         从ApplicationContext接口的实现,我们看出其特点:

         1.  支持信息源,可以实现国际化。(实现MessageSource接口)

         2.  访问资源。(实现ResourcePatternResolver接口,这个后面要讲)

         3.  支持应用事件。(实现ApplicationEventPublisher接口)


         我们看ClassPathXmlApplicationContext是如何建立IOC容器,先看其构造函数:

[java]  view plain copy
  1. public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
  2.             throws BeansException {  
  3.   
  4.         super(parent);  
  5.         setConfigLocations(configLocations);  
  6.         if (refresh) {  
  7.             refresh();  
  8.         }  
  9.     }  

         refresh的模板是在AbstractApplicationContext中:

[java]  view plain copy
  1. public void refresh() throws BeansException, IllegalStateException {  
  2.         synchronized (this.startupShutdownMonitor) {  
  3.             // Prepare this context for refreshing.  
  4.             prepareRefresh();  
  5.   
  6.             // Tell the subclass to refresh the internal bean factory.  
  7.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.   
  9.             // Prepare the bean factory for use in this context.  
  10.             prepareBeanFactory(beanFactory);  
  11.   
  12.             try {  
  13.                 // Allows post-processing of the bean factory in context subclasses.  
  14.                 postProcessBeanFactory(beanFactory);  
  15.                 // Invoke factory processors registered as beans in the context.  
  16.                 invokeBeanFactoryPostProcessors(beanFactory);  
  17.   
  18.                 // Register bean processors that intercept bean creation.  
  19.                 registerBeanPostProcessors(beanFactory);  
  20.   
  21.                 // Initialize message source for this context.  
  22.                 initMessageSource();  
  23.   
  24.                 // Initialize event multicaster for this context.  
  25.                 initApplicationEventMulticaster();  
  26.   
  27.                 // Initialize other special beans in specific context subclasses.  
  28.                 onRefresh();  
  29.   
  30.                 // Check for listener beans and register them.  
  31.                 registerListeners();  
  32.   
  33.                 // Instantiate all remaining (non-lazy-init) singletons.  
  34.                 finishBeanFactoryInitialization(beanFactory);  
  35.   
  36.                 // Last step: publish corresponding event.  
  37.                 finishRefresh();  
  38.             }  
  39.             ……  
这里是我们分析的入口,其完成了整个的bean初始化过程。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

spring IOC源码分析(2)

分类: SSH学习   518人阅读  评论(0)  收藏  举报
        refresh这个方法包含了整个BeanFactory初始化的过程,定位资源由obtainFreshBeanFactory()来完成,
[java]  view plain copy
  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
  2.         refreshBeanFactory();  
  3.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
  4.         if (logger.isDebugEnabled()) {  
  5.             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
  6.         }  
  7.         return beanFactory;  
  8.     }  

         可以看到其调用了refreshBeanFactory(),refreshBeanFactory()在这个类中是抽象方法,其实现在AbstractRefreshableApplicationContext中。

[java]  view plain copy
  1. protected final void refreshBeanFactory() throws BeansException {  
  2.         if (hasBeanFactory()) {  
  3.             destroyBeans();  
  4.             closeBeanFactory();  
  5.         }  
  6.         try {  
  7.             DefaultListableBeanFactory beanFactory = createBeanFactory();  
  8.             beanFactory.setSerializationId(getId());  
  9.             customizeBeanFactory(beanFactory);  
  10.             loadBeanDefinitions(beanFactory);  
  11.             synchronized (this.beanFactoryMonitor) {  
  12.                 this.beanFactory = beanFactory;  
  13.             }  
  14.         }  
  15.         catch (IOException ex) {  
  16.             ……  
  17.         }  
  18. }  

          在这个方法中,先判断BeanFactory是否存在,如果存在则先销毁beans并关闭beanFactory,接着创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义。loadBeanDefinitions方法同样是抽象方法,是由其子类实现的,也即在AbstractXmlApplicationContext中。

[java]  view plain copy
  1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {    
  2.    <span style="color:#33ff33;"// 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件</span>    
  3.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);    
  4.     
  5.     <span style="color:#33ff33;">//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的</span>    
  6.  <span style="color:#33ff33;">   //因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader </span>   
  7.     beanDefinitionReader.setResourceLoader(this);    
  8.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));    
  9.     
  10.     initBeanDefinitionReader(beanDefinitionReader);    
  11.     <span style="color:#33ff33;">//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理</span>    
  12.     loadBeanDefinitions(beanDefinitionReader);    
  13. }    

          接着我们转到beanDefinitionReader中进行处理

[java]  view plain copy
  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {    
  2.     Resource[] configResources = getConfigResources();    
  3.     if (configResources != null) {    
  4.       <span style="color:#33ff33;">  //调用XmlBeanDefinitionReader来载入bean定义信息。</span>    
  5.         reader.loadBeanDefinitions(configResources);    
  6.     }    
  7.     String[] configLocations = getConfigLocations();    
  8.     if (configLocations != null) {    
  9.         reader.loadBeanDefinitions(configLocations);    
  10.     }    
  11. }    

         可以到org.springframework.beans.factory.support看一下BeanDefinitionReader的结构

        在其抽象父类AbstractBeanDefinitionReader中定义了载入过程

 

[java]  view plain copy
  1. public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {    
  2.    <span style="color:#33ff33;"//这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader </span>   
  3.     ResourceLoader resourceLoader = getResourceLoader();    
  4.     <span style="color:#33ff33;">//如果没有找到我们需要的ResourceLoader,直接抛出异常</span>    
  5.     if (resourceLoader instanceof ResourcePatternResolver) {    
  6.         <span style="color:#33ff33;">// 这里处理我们在定义位置时使用的各种pattern,需要 ResourcePatternResolver来完成</span>    
  7.         try {    
  8.             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);    
  9.             int loadCount = loadBeanDefinitions(resources);    
  10.             return loadCount;    
  11.         }    
  12.         ........    
  13.     }    
  14.     else {    
  15.         <span style="color:#33ff33;">// 这里通过ResourceLoader来完成位置定位</span>    
  16.         Resource resource = resourceLoader.getResource(location);    
  17.             <span style="color:#33ff33;"// 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了</span>    
  18.         int loadCount = loadBeanDefinitions(resource);    
  19.         return loadCount;    
  20.     }    
  21. }   



 


        看到第8、16行,结合上面的ResourceLoader与ApplicationContext的继承关系图,可以知道此时调用的是DefaultResourceLoader中的getSource()方法定位Resource,因为ClassPathXmlApplicationContext本身就是DefaultResourceLoader的实现类,所以此时又回到了ClassPathXmlApplicationContext中来。

 

        继续回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法看得到代表bean文件的资源定义以后的载入过程。

[java]  view plain copy
  1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    
  2.     .......    
  3.     try {    
  4.         <span style="color:#33ff33;">//这里通过Resource得到InputStream的IO流</span>    
  5.         InputStream inputStream = encodedResource.getResource().getInputStream();    
  6.         try {    
  7.            <span style="color:#33ff33;"//从InputStream中得到XML的解析源</span>    
  8.             InputSource inputSource = new InputSource(inputStream);    
  9.             if (encodedResource.getEncoding() != null) {    
  10.                 inputSource.setEncoding(encodedResource.getEncoding());    
  11.             }    
  12.             <span style="color:#33ff33;">//这里是具体的解析和注册过程</span>    
  13.             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());    
  14.         }    
  15.         finally {    
  16.             <span style="BACKGROUND-COLOR: #33ff33">//关闭从Resource中得到的IO流</span>    
  17.             inputStream.close();    
  18.         }    
  19.     }    
  20.        .........    
  21. }    
  22.     
  23. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)    
  24.         throws BeanDefinitionStoreException {    
  25.     try {    
  26.         int validationMode = getValidationModeForResource(resource);    
  27.         <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span>    
  28.         Document doc = this.documentLoader.loadDocument(    
  29.                 inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);    
  30.         return registerBeanDefinitions(doc, resource);    
  31.     }    
  32. .......    
  33. }  

        在doLoadBeanDefinitions(…)先把定义文件解析为DOM对象,然后进行具体的注册过程。

[java]  view plain copy
  1. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
  2.         <span style="color:#33ff33;">//具体的注册过程,首先得到XmlBeanDefinitionDocumentReader来处理xml的bean定义文件</span>  
  3.         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
  4.         documentReader.setEnvironment(this.getEnvironment());  
  5.         int countBefore = getRegistry().getBeanDefinitionCount();  
  6.         <span style="color:#33ff33;">//调用注册方法</span>  
  7.                      documentReader.registerBeanDefinitions(doc,createReaderContext(resource));  
  8.              return getRegistry().getBeanDefinitionCount() - countBefore;  
  9. }  
  10. <p> </p>  

 

        具体的过程在BeanDefinitionDocumentReader中完成,在DefaultBeanDefinitionDocumentReader的方法中完成bean定义文件的解析和IOC容器中bean的初始化。

[java]  view plain copy
  1. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
  2.         this.readerContext = readerContext;  
  3.   
  4.         logger.debug("Loading bean definitions");  
  5.         Element root = doc.getDocumentElement();  
  6.   
  7.         doRegisterBeanDefinitions(root);  
  8. }  

 

[java]  view plain copy
  1. protected void doRegisterBeanDefinitions(Element root) {  
  2.         <span style="color:#33ff33;">……(注:省略号表示省略掉了代码)  
  3.         //通过代理delegate解析</span>  
  4.         BeanDefinitionParserDelegate parent = this.delegate;  
  5.         this.delegate = createHelper(readerContext, root, parent);  
  6.   
  7.         preProcessXml(root);  
  8.         parseBeanDefinitions(root, this.delegate);  
  9.         postProcessXml(root);  
  10.   
  11.         this.delegate = parent;  
  12. }  

 

[java]  view plain copy
  1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
  2.         if (delegate.isDefaultNamespace(root)) {  
  3.             <span style="color:#33ff33;">//得到xml文件的子节点,比如各个bean节点</span>  
  4.             NodeList nl = root.getChildNodes();  
  5.             <span style="color:#33ff33;">//对每个节点进行分析处理</span>  
  6.             for (int i = 0; i < nl.getLength(); i++) {  
  7.                 Node node = nl.item(i);  
  8.                 if (node instanceof Element) {  
  9.                     Element ele = (Element) node;  
  10.                     if (delegate.isDefaultNamespace(ele)) {  
  11.                         <span style="color:#33ff33;">//这里是解析过程的调用,对缺省的元素进行分析比如bean元素</span>  
  12.                         parseDefaultElement(ele, delegate);  
  13.                     }  
  14.                     else {  
  15.                         delegate.parseCustomElement(ele);  
  16.                     }  
  17.                 }  
  18.             }  
  19.         }  
  20.         else {  
  21.             delegate.parseCustomElement(root);  
  22.         }  
  23. }  

 

[java]  view plain copy
  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.         <span style="color:#33ff33;">//对元素Import进行处理</span>  
  3.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
  4.             importBeanDefinitionResource(ele);  
  5.         }  
  6.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
  7.             processAliasRegistration(ele);  
  8.         }  
  9.         <span style="color:#33ff33;">//对我们熟悉的bean元素进行处理</span>  
  10.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
  11.             processBeanDefinition(ele, delegate);  
  12.         }  
  13.         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
  14.             <span style="color:#33ff33;">// recurse</span>  
  15.             doRegisterBeanDefinitions(ele);  
  16.         }  
  17. }  
[java]  view plain copy
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
  2.         <span style="color:#33ff33;">//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包括了具体的bean解析过程。把解析bean文件得到的信息放在BeanDefinition里,它是bean信息的主要载体,也是IOC容器的管理对象。</span>  
  3.         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
  4.         if (bdHolder != null) {  
  5.              bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
  6.             try {  
  7.                 <span style="color:#33ff33;">// Register the final decorated instance.  
  8.                                //向IOC容器注册,实际是放到IOC容器的一个map里</span>         
[java]  view plain copy
  1.                                   BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
  2.     }  
  3.     catch (BeanDefinitionStoreException ex) {  
  4.         ……  
  5.     }  
  6.     <span style="color:#33ff33;">// Send registration event.  
  7.     //这里向IOC容器发送事件,表示解析和注册完成</span>  
  8.                     getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
  9. }  

         可以看到在processBeanDefinition中对具体bean元素的解析是交给BeanDefinitionParserDelegate来完成的。我们接着看其实现的函数:

[java]  view plain copy
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
  2.         <span style="color:#33ff33;">……(省略)</span>  
  3.         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
  4.         if (beanDefinition != null) {  
  5.             <span style="color:#33ff33;">//BeanDefinition解析过程</span>  
  6.                                 ……(省略)  
  7.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
  8.                            <span style="color:#33ff33;">//将解析完的bean定义包装后返回</span>  
  9.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
  10.         }  
  11.         return null;  
  12. }  
  13. <p> </p>  


         在这里对定义文件中的bean元素进行解析,得到AbstractBeanDefinition,并用BeanDefinitionHolder封装后返回。

        下面我们看解析完的bean如何在IOC容器中注册:在BeanDefinitionReaderUtils中调用的是:

[java]  view plain copy
  1. public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
  2. throws BeanDefinitionStoreException {  
  3.         <span style="color:#33ff33;">// Register bean definition under primary name.  
  4.         //得到需要注册bean的名字</span>  
  5.         String beanName = definitionHolder.getBeanName();  
  6.         <span style="color:#33ff33;">//调用IOC来注册bean的过程,需要得到BeanDefinition</span>  
  7.         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
  8.   
  9.         <span style="color:#33ff33;">// Register aliases for bean name, if any.  
  10.         //将别名通过IOC容器和bean联系起来进行注册</span>  
  11.         String[] aliases = definitionHolder.getAliases();  
  12.         if (aliases != null) {  
  13.             for (String aliase : aliases) {  
  14.                 registry.registerAlias(beanName, aliase);  
  15.             }  
  16.         }  
  17. }  


         接着我们看看bean的注册实现,从上面看到其调用的是BeanDefinitionRegistry的方法registerBeanDefinition完成注册,跟踪代码可知BeanFactory容器的一个实现DefaultListableBeanFactory实现了这个接口并提供了注册的具体实现:

 

[java]  view plain copy
  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {  
  2.   
  3.         ......  
  4.         if (beanDefinition instanceof AbstractBeanDefinition) {  
  5.             try {  
  6.                 ((AbstractBeanDefinition) beanDefinition).validate();  
  7.             }  
  8.             catch (BeanDefinitionValidationException ex) {  
  9.                 <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
  10.                 ……  
  11.             }  
  12.         }  
  13.   
  14.         synchronized (this.beanDefinitionMap) {  
  15.             Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
  16.             if (oldBeanDefinition != null) {  
  17.                 if (!this.allowBeanDefinitionOverriding) {  
  18.                     <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
  19.                     ……  
  20.                 }  
  21.                 else {  
  22.                     if (this.logger.isInfoEnabled()) {  
  23.                         ……  
  24.                     }  
  25.                 }  
  26.             }  
  27.             else {  
  28.                 this.beanDefinitionNames.add(beanName);  
  29.                 this.frozenBeanDefinitionNames = null;  
  30.             }  
  31.             this.beanDefinitionMap.put(beanName, beanDefinition);  
  32.   
  33.             resetBeanDefinition(beanName);  
  34.         }  
  35. }  

         可以看到整个注册过程很简单,就是将bean添加到BeanDefinition的map中。这样就完成了bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Spring IOC源码分析(3)

分类: SSH学习   415人阅读  评论(0)  收藏  举报

1.IOC容器的依赖注入

        Spring中,依赖注入是在用户第一次向IOC容器索要Bean时触发的(通过getBean方法)。

       在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中:

[java]  view plain copy
  1. public Object getBean(String name) throws BeansException {  
  2.         return doGetBean(name, nullnullfalse);  
  3. }  

        可以看到具体的注入过程转移到doGetBean(String…)中,在这个方法中,它首先从缓存中取,如果单件模式的bean已经被创建,则这种bean请求不需要重复的创建,调用

[java]  view plain copy
  1. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  

        跟踪进入getObjectForBeanInstance(…,null),可以知道因为最后的RootBeanDefinition参数是null,所以执行的是:

[java]  view plain copy
  1. if (mbd == null) {  
  2.     object = getCachedObjectForFactoryBean(beanName);  
  3. }  

        而getCachedObjectForFactoryBean(beanName)中实现,其实现很简单,就是在缓存的bean map中查找bean返回。

        继续回到doGetBean(String…)方法中:

[java]  view plain copy
  1.          //取当前bean的所有依赖bean,这样就会触发getBean的递归调用,直至取到一个没有任何依赖的bean为止  
  2.     String[] dependsOn = mbd.getDependsOn();  
  3.     if (dependsOn != null) {  
  4.         for (String dependsOnBean : dependsOn) {  
  5.             getBean(dependsOnBean);  
  6.                       //注册依赖的bean实例,具体实现过程在DefaultSingletonBeanRegistry中实现,其实就是将依赖的bean添加到依赖的hashmap中  
  7.             registerDependentBean(dependsOnBean, beanName);  
  8.         }  
  9.     }  
  10.     //通过调用createBean来,创建单例bean的实例  
  11.     if (mbd.isSingleton()) {  
  12.         sharedInstance = getSingleton(beanName, new ObjectFactory() {  
  13.            public Object getObject() throws BeansException {  
  14.              try {  
  15.               return createBean(beanName, mbd, args);  
  16.              }  
  17.              catch (BeansException ex) {  
  18.             destroySingleton(beanName);  
  19.             throw ex;  
  20.              }  
  21.                 }  
  22.             });  
  23.             bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);  
  24.     }  
  25.     //同样调用createBean创建prototype的bean实例  
  26.     else if (mbd.isPrototype()) {  
  27.         // It's a prototype -> create a new instance.  
  28.         Object prototypeInstance = null;  
  29.         try {  
  30.             beforePrototypeCreation(beanName);  
  31.             prototypeInstance = createBean(beanName, mbd, args);  
  32.         }  
  33.         finally {  
  34.             afterPrototypeCreation(beanName);  
  35.         }  
  36.         bean=getObjectForBeanInstance(prototypeInstance,name, beanName, mbd);  
  37. }  

        继续看createBean(…),可以看到在AbstractBeanFactory中它只是个抽象类,具体的实现交给其子类(又见模板模式),进入子类AbstractAutowireCapableBeanFactory中看createBean的具体实现:

[java]  view plain copy
  1. Object beanInstance = doCreateBean(beanName, mbd, args);  


        其具体的实现转到doCreateBean(String…),这里我们看到与依赖注入关系比较密切的方法有createBeanInstance和populateBean。

[java]  view plain copy
  1. BeanWrapper instanceWrapper = null;  
  2. if (mbd.isSingleton()) {  
  3.     instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
  4. }  
  5. if (instanceWrapper == null) {  
  6.     instanceWrapper = createBeanInstance(beanName, mbd, args);  
  7. }  


[java]  view plain copy
  1. // Initialize the bean instance.  
  2. Object exposedObject = bean;  
  3. try {  
  4.     populateBean(beanName, mbd, instanceWrapper);  
  5.     if (exposedObject != null) {  
  6.         exposedObject = initializeBean(beanName, exposedObject, mbd);  
  7.     }  
  8. }  

        在createBeanInstance中生成了Bean所包含的Java对象,这个对象的生成有很多不同的方式,可以通过工厂方法生成,也可以通过容器的autowire特性生成,生成的方式由相关联的BeanDefinition来指定,进入createBeanInstance方法,有:

[java]  view plain copy
  1. return instantiateUsingFactoryMethod(beanName, mbd, args);  


[java]  view plain copy
  1. return instantiateBean(beanName, mbd);  


        上面是其中的两个实例化方法,上面的是在BeanDefinition的FactoryMethod存在的情况下,使用工厂方法对bean进行实例化。下面一个是使用默认的构造函数对bean进行实例化。我们进入instantiateBean(beanName,mbd),可以看到有:

[java]  view plain copy
  1. return getInstantiationStrategy().instantiate(mbd, beanName, parent);  


        因为getInstantiationStrategy()返回的默认的实例化策略,而默认的实例化策略是CglibSubclassingInstantiationStrategy,也即用cglib来对bean进行实例化。CGLIB是一个常用的字节码生成器的类库,它提供了一系列的API来提供Java的字节码生成和转换功能。

        我们再次回到doCreateBean()中的populateBean方法,看看在实例化Bean对象生成的基础上,spring怎样把这些bean对象的依赖关系设置好,完成整个依赖注入过程。在populateBean中,先是取得在BeanDefinition中设置的property值,这些property来自对BeanDefinition的解析,接着便开始进行依赖注入过程:

[java]  view plain copy
  1. //开始进行依赖注入过程,先处理autowire的注入  
  2. if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
  3.             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
  4.   
  5.             //根据bean的名字进行autowire过程  
  6.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
  7.                 autowireByName(beanName, mbd, bw, newPvs);  
  8.             }  
  9.   
  10.             //根据类型type进行autowire的过程  
  11.             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
  12.                 autowireByType(beanName, mbd, bw, newPvs);  
  13.             }  
  14.   
  15.             pvs = newPvs;  
  16. }  

         最后在通过applyPropertyValues对属性进行注入:

[java]  view plain copy
  1. applyPropertyValues(beanName, mbd, bw, pvs);  


         接着我们到applyPropertyValues中去看具体的对属性进行解析然后注入的过程,在其中会调用BeanDefinitionValueResolver对BeanDefinition进行解析,


[java]  view plain copy
  1. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);  


         接着为解析值创建一个拷贝,拷贝的数据将会被注入到bean中,它会先对PropertyValue判断,如果其没有经过转换则会调用resolveValueIfNecessary进行解析,然后注入到property中。下面到BeanDefinitionValueResolver中去看一下解析过程的实现,在函数resolveValueIfNecessary中包含了所有对注入类型的处理,以RuntimeBeanReference(其是在对BeanDefinition进行解析时生成的数据对象)为例:


[java]  view plain copy
  1. if (value instanceof RuntimeBeanReference) {  
  2.     RuntimeBeanReference ref = (RuntimeBeanReference) value;  
  3.     return resolveReference(argName, ref);  
  4. }  
  5. //当注入类型为RuntimeBeanReference时,进入resolveReference(…):  
  6. private Object resolveReference(Object argName, RuntimeBeanReference ref) {  
  7.         try {  
  8.             //从RuntimeBeanReference取得reference的名字  
  9.             String refName = ref.getBeanName();  
  10.             refName = String.valueOf(evaluate(refName));  
  11.             //如果ref是在双亲的IOC容器中,那就到双亲IOC容器中去取  
  12.             if (ref.isToParent()) {  
  13.                 if (this.beanFactory.getParentBeanFactory() == null) {  
  14.                     //抛出异常BeanCreationException  
  15.                                              ……  
  16.                 }  
  17.                 return this.beanFactory.getParentBeanFactory().  
  18.                                      getBean(refName);  
  19.             }  
  20.             else {  
  21.                                     //在当前IOC容器中去取bean  
  22.                 Object bean = this.beanFactory.getBean(refName);  
  23.                                 this.beanFactory.registerDependentBean(refName, this.beanName);  
  24.                 return bean;  
  25.             }  
  26. }  

        在上面的实现中,无论是到双亲的IOC容器中去取,还是在当前IOC容器中取,都会触发一个getBean的过程,这就触发了相应的依赖注入的发生。

 

        这就完成了resolve的过程,为依赖注入准备好了条件。但真正的把Bean对象设置到它所依赖的另一个Bean的属性中去的地方是在BeanWrapper的setPropertyValues中(在分析populateBean的时候有提到),其中处理的属性是各种各样的。setPropertyValues的具体实现是在BeanWrapper的子类BeanWrapperImpl中:

        在doCreateBean中执行完populateBean,完成Bean的生成和依赖注入以后,开始对Bean进行初始化,这个初始化过程包含了对后置处理器的postProcessBeforeInitializtion回调,具体实现在initializeBean方法中:

[java]  view plain copy
  1. Object wrappedBean = bean;  
  2. if (mbd == null || !mbd.isSynthetic()) {  
  3.     wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
  4. }  
  5.   
  6. try {  
  7.     invokeInitMethods(beanName, wrappedBean, mbd);  
  8. }  
  9. catch (Throwable ex) {  
  10.     //抛出异常BeanCreationException  
  11. }  
  12.   
  13. if (mbd == null || !mbd.isSynthetic()) {  
  14.     wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
  15. }  
  16. return wrappedBean;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值