Springソース解析1 IOC容器の初期化


「Spring技術の裏側」を参照してください.  
 IoC容器の基本インターフェースはBenFactoryによって定義されています.つまりBenFactoryはIoC容器の最も基本的な形を定義し、提供されました.  IoC容器が守るべき基本的なサービス契約.ビーンファクトリーはインターフェースクラスだけで、容器の具体的な実現は与えられていません.DefaultListable BeanFactory、XmlBenFactory、Apple Controtext、FileSystemXlBenFactory、Class PathXml Beacon FactoryはBenFactoryインターフェースを実現し、IoC容器の機能を拡張しました.
まずBenFactoryを紹介します.
 
public interface BeanFactory {      
     
    //    FactoryBean     ,      bean     FactoryBean             ,      
    //          ,                 
    String FACTORY_BEAN_PREFIX = "&";      
     
     
    //    bean   , IOC     bean  ,  IOC            。      
    Object getBean(String name) throws BeansException;      
     
    //    bean    Class     bean  ,                :         bean   Class          。      
    Object getBean(String name, Class requiredType) throws BeansException;      
     
    //     bean   ,     IOC        bean      
    boolean containsBean(String name);      
     
    //    bean    bean  ,       bean           
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;      
     
    //     bean   Class        
    Class getType(String name) throws NoSuchBeanDefinitionException;      
     
    //    bean   ,        ,                  
    String[] getAliases(String name);      
     
}    
 
 
ユーザが容器を使用する場合は、トランス義文字'&'を使用してFactoryBean自体を得ることができ、容器を通してFactoryBeanが生成したオブジェクトを取得するか、それともFactoryBean自体を取得するかを区別するために使用されます.Springでは全てのBeanはBenFactoryで管理されていますが、FactoryBeanに対しては、オブジェクトを生成または修飾することができる工場Beanです.
BenFactoryとFactoryBean:BenFactoryはIoC容器のプログラミング抽象を指しますが、FactoryBeanは抽象的な工場を指しています.その呼び出しに対して工場が生み出す対象はそれ自体ではありません.
 
 
 
 
 
まずプログラミングによってIoC容器を実現します.
 
public class UserBeanFatory {   
    public static void main(String[] args) {   
        //    BeanFactory,    DefaultListableBeanFactory,  IoC          
        DefaultListableBeanFactory factory=new DefaultListableBeanFactory();   
        /*  
         *       BeanDefinition    ,    XmlBeanDefinitionReader   XML       
         * BeanDefinition,         BeanFactory  
         */  
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);   
        /*  
         *   Ioc         ,          BeanDefinition       
         */  
        ClassPathResource res=new ClassPathResource("applicationContext-beans.xml");   
        /*  
         *                ,         XmlBeanDefinitionReader  
         *     。          Bean    ,   IoC          
         */  
        reader.loadBeanDefinitions(res);   
  
        User user=(User)factory.getBean("user");   
        System.out.println(user.getUsername()+":"+user.getPassword());   
        //      
        XmlBeanFactory xmlfactory=new XmlBeanFactory(new ClassPathResource("applicationContext-beans.xml"));   
        User xmluser=(User)factory.getBean("user");   
        System.out.println(xmluser.getUsername()+":"+xmluser.getPassword());   
        ApplicationContext ac=new FileSystemXmlApplicationContext("D:/java/kcsj/SourceXmpBeanFactory/src/applicationContext-beans.xml");   
        ac.getBean("user");   
    }   
  
}  
 
 
 
 上記からIoC容器初期化は三つのステップに分けられると考えられます.
1 BenDefinitionのResource位置付け
2 BeanDefinitionのロードと解析
3 BeanDefinitionの登録
 
まずBenDefinitionのResource位置を見ます.
以下はFileSystemXml Application Contectを例にとって、このApplication Contectの実現を分析することによって、Resourceの位置付けがどのように完了したかを見てみます.
Apple Comptext ac=new FileSystemXml Apple Controtext("D:/java/kcsj/SourceXmpBenFactory/src/appication Controtext-beans.xml");
 
 
 

 

我们首先看看FileSystemXmlApplicationContext的源码:

 

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {   
      .....   
      public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)   
            throws BeansException {   
  
        super(parent);   
        setConfigLocations(configLocations);   
        if (refresh) {   
            refresh();   
        }   
     }  
 
 

}

 

在FileSystemXmlApplicationContext 的构造函数中完成了两部分功能:1是设置BeanDefinition的配置文件的路径,是的所有在配置文件中的BeanDefinition都能得到有效地处理;2 就是通过refresh()方法启动了IoC容器的初始化。

AbstractApplicationContext的refresh()方法源码解析:

public void refresh() throws BeansException, IllegalStateException {   
        synchronized (this.startupShutdownMonitor) {   
            // Prepare this context for refreshing.   
            prepareRefresh();   
  
            // Tell the subclass to refresh the internal bean factory.   
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();   
  
            // Prepare the bean factory for use in this context.   
            prepareBeanFactory(beanFactory);   
  
            try {   
                // Allows post-processing of the bean factory in context subclasses.   
                postProcessBeanFactory(beanFactory);   
  
                // Invoke factory processors registered as beans in the context.   
                invokeBeanFactoryPostProcessors(beanFactory);   
  
                // Register bean processors that intercept bean creation.   
                registerBeanPostProcessors(beanFactory);   
  
                // Initialize message source for this context.   
                initMessageSource();   
  
                // Initialize event multicaster for this context.   
                initApplicationEventMulticaster();   
  
                // Initialize other special beans in specific context subclasses.   
                onRefresh();   
  
                // Check for listener beans and register them.   
                registerListeners();   
  
                // Instantiate all remaining (non-lazy-init) singletons.   
                finishBeanFactoryInitialization(beanFactory);   
  
                // Last step: publish corresponding event.   
                finishRefresh();   
            }   
  
            catch (BeansException ex) {   
                // Destroy already created singletons to avoid dangling resources.   
                destroyBeans();   
  
                // Reset 'active' flag.   
                cancelRefresh(ex);   
  
                // Propagate exception to caller.   
                throw ex;   
            }   
        }   
    }  
 
 IoC容器の全体初期化のプロセスを含み、ビーンFactoryの更新、初期化message source、構成と登録後のプロセッサ、モニターとイベントトリガーの登録、およびプリユーティリティ(non-lazy-nit)の処理などがあります.それは資源の位置付けをオーブタインFreeshBeanFactory方法に任せました.
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {   
    refreshBeanFactory();   
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();   
    if (logger.isDebugEnabled()) {   
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);   
    }   
    return beanFactory;   
}  
 
 そして抽象的な方法を呼び出すことによってrefreshaBenFactoryは、Abstractrefreshable AppleicaitonContectで実現される:
protected final void refreshBeanFactory() throws BeansException {   
        if (hasBeanFactory()) {   
            destroyBeans();   
            closeBeanFactory();   
        }   
        try {   
            DefaultListableBeanFactory beanFactory = createBeanFactory();   
            beanFactory.setSerializationId(getId());   
            customizeBeanFactory(beanFactory);   
            loadBeanDefinitions(beanFactory);   
            synchronized (this.beanFactoryMonitor) {   
                this.beanFactory = beanFactory;   
            }   
        }   
        catch (IOException ex) {   
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);   
        }   
    }  
 
 
ここでまずビーンファクトリーが確立されているかどうかを判断し、確立すればビーンファクトリーを破棄してクローズし、ビーンファクトリーを作成します.ここで作成されたのはDefault Listable BeanFactoryです.その後、loadBeanDefinitionsがBeanDefinitionにロードする配置情報を呼び出します.次に私達はloadBeanDefinitions方法の具体的な実行過程を見に行きます.
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {   
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.   
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);   
  
    // Configure the bean definition reader with this context's   
    // resource loading environment.   
    beanDefinitionReader.setResourceLoader(this);   
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));   
  
    // Allow a subclass to provide custom initialization of the reader,   
    // then proceed with actually loading the bean definitions.   
    initBeanDefinitionReader(beanDefinitionReader);   
    loadBeanDefinitions(beanDefinitionReader);   
}  
 
 
ここではまずビーンDefinitionのXmlリーダーを作成し、ビーンFactoryにフィードバックして構成します.これは前のプログラミングによってIoC容器の初期化を実現した後、またloadBeabin Definitionsに移行します.
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   
        Resource[] configResources = getConfigResources();   
        if (configResources != null) {   
            reader.loadBeanDefinitions(configResources);   
        }   
        String[] configLocations = getConfigLocations();   
        if (configLocations != null) {   
            reader.loadBeanDefinitions(configLocations);   
        }   
    }  
 
 最初にビーンDefinitionのプロファイルのリソースを取得し、存在するかどうかを判断し、ロードしてからプロファイルのパスを取得し、存在するかどうかを判断し、存在する場合はロードする.一つはリソースからロードされ、もう一つは与えられたパスからロードされる.私たちは明示的な定義リソースがないので、設定ファイルのパスを与えただけです.だから、パスからロードします.つまりreader.loadBenDefinitionsを呼び出す方法です.
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {   
    Assert.notNull(locations, "Location array must not be null");   
    int counter = 0;   
    for (String location : locations) {   
        counter += loadBeanDefinitions(location);   
    }   
    return counter;   
}  
 
 
次に、loadBeanDefinitionsメソッドを呼び出します.
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {   
        return loadBeanDefinitions(location, null);   
    }  
 
 転じて:loadBenDefinitions(String location、Set<Resource>actualResource)方法で
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {   
        ResourceLoader resourceLoader = getResourceLoader();   
        if (resourceLoader == null) {   
            throw new BeanDefinitionStoreException(   
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");   
        }   
  
        if (resourceLoader instanceof ResourcePatternResolver) {   
            // Resource pattern matching available.   
            try {   
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);   
                int loadCount = loadBeanDefinitions(resources);   
                if (actualResources != null) {   
                    for (Resource resource : resources) {   
                        actualResources.add(resource);   
                    }   
                }   
                if (logger.isDebugEnabled()) {   
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");   
                }   
                return loadCount;   
            }   
            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 loadCount = loadBeanDefinitions(resource);   
            if (actualResources != null) {   
                actualResources.add(resource);   
            }   
            if (logger.isDebugEnabled()) {   
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");   
            }   
            return loadCount;   
        }   
    }  
 
 Resource resource=resource Loader.get Resource(location)BenDefinitionのリソースを特定するために使用されます.Default Resource Loaderのget Resource()方法によって処理されます.
public Resource getResource(String location) {   
    Assert.notNull(location, "Location must not be null");   
    if (location.startsWith(CLASSPATH_URL_PREFIX)) {   
        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());   
    }   
    else {   
        try {   
            // Try to parse the location as a URL...   
            URL url = new URL(location);   
            return new UrlResource(url);   
        }   
        catch (MalformedURLException ex) {   
            // No URL -> resolve as resource path.   
            return getResourceByPath(location);   
        }   
    }   
}  
 
 最後にそれはまたgetsResource ByPathを呼び出して、FileSystemXmlAppleication Contectの中でgetResource ByPath()によって覆われました.具体的なソースは以下の通りです.
protected Resource getResourceByPath(String path) {   
    if (path != null && path.startsWith("/")) {   
        path = path.substring(1);   
    }   
    return new FileSystemResource(path);   
} 
 
 ここまでIoC容器の初期化の第一ステップは完了しました.総括できるBeabin DefinitionのResourceの位置付けはDefault Resource Loaderによってgets Resource()メソッドが位置しています.getsResource()ではまたgets Resource ByPath()を呼び出して、それは異なるBenFactoryによって上書きされます.