spring源码解析- IOC

1.何谓spring IOC

    何谓Spring IOC?书上谓之“依赖注入”,那何谓“依赖注入”?
    作为一个Java程序猿,应该遇到过这样的问题,当你在代码中需要使用某个类提供的功能时,你首先需要new一个对象,给它传递必要的参数,然后才能使用它提供的功能,最后释放对象占用的内存,当然了这个在Java不需要你自己去干了。这也就是说你需要自己去管理变量的整个生命周期,这在大型项目中是很糟糕的。现在好了,有了Spring IOC,这些事情都不需要你去做,你只需要告诉Spring你需要的变量实例,配置其对应关系,Spring就可以讲你依赖的实例注入到你的变量中。
    使用spring管理Java类的好处就是,你不需要自己去创建类的实例,所有的类(主要是service  controller  )创建全部由spring完成,默认是单例的。节省JVM的堆内存,同时为AOP动态代理的使用买下伏笔。
    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容器接口:
1.  public interface BeanFactory {  
2.    
3.  //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索     FactoryBean得到的对象是工厂生成的对象,  
4.  //如果需要得到工厂本身,需要转义         
5.  String FACTORY_BEAN_PREFIX = "&";  
6.    
7.    
8.    //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。  
9.      Object getBean(String name) throws BeansException;  
10.   
11.   //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。  
12.     Object getBean(String name, Class requiredType) throws BeansException;  
13.   
14. //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean  
15.     boolean containsBean(String name);  
16.   
17.     //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件  
18.     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  
19.   
20.     //这里对得到bean实例的Class类型  
21.     Class getType(String name) throws NoSuchBeanDefinitionException;  
22.   
23.     //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  
24.     String[] getAliases(String name);  
25.   
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容器,先看其构造函数:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
            throws BeansException {  

        super(parent);  
        setConfigLocations(configLocations);  
        if (refresh) {  
            refresh();  
        }  
    }  

refresh的模板是在AbstractApplicationContext中:

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();  
            }  
            ……  

里是我们分析的入口,其完成了整个的bean初始化过程。

refresh这个方法包含了整个BeanFactory初始化的过程,定位资源由obtainFreshBeanFactory()来完成,

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
        refreshBeanFactory();  
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
        if (logger.isDebugEnabled()) {  
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
        }  
        return beanFactory;  
    }  

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

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) {  
            ……  
        }  
}  

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

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {    
   <span style="color:#33ff33;"> // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件</span>    
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);    

    <span style="color:#33ff33;">//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的</span>    
 <span style="color:#33ff33;">   //因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader </span>   
    beanDefinitionReader.setResourceLoader(this);    
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));    

    initBeanDefinitionReader(beanDefinitionReader);    
    <span style="color:#33ff33;">//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理</span>    
    loadBeanDefinitions(beanDefinitionReader);    
} 

接着我们转到beanDefinitionReader中进行处理,在其抽象父类AbstractBeanDefinitionReader中定义了载入过程

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

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

    继续回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法看得到代表bean文件的资源定义以后的载入过程。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {    
    .......    
    try {    
        <span style="color:#33ff33;">//这里通过Resource得到InputStream的IO流</span>    
        InputStream inputStream = encodedResource.getResource().getInputStream();    
        try {    
           <span style="color:#33ff33;"> //从InputStream中得到XML的解析源</span>    
            InputSource inputSource = new InputSource(inputStream);    
            if (encodedResource.getEncoding() != null) {    
                inputSource.setEncoding(encodedResource.getEncoding());    
            }    
            <span style="color:#33ff33;">//这里是具体的解析和注册过程</span>    
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());    
        }    
        finally {    
            <span style="BACKGROUND-COLOR: #33ff33">//关闭从Resource中得到的IO流</span>    
            inputStream.close();    
        }    
    }    
       .........    
}    

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)    
        throws BeanDefinitionStoreException {    
    try {    
        int validationMode = getValidationModeForResource(resource);    
        <span style="color:#33ff33;">//通过解析得到DOM,然后完成bean在IOC容器中的注册</span>    
        Document doc = this.documentLoader.loadDocument(    
                inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);    
        return registerBeanDefinitions(doc, resource);    
    }    
.......    
}  

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

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

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

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
        this.readerContext = readerContext;  

        logger.debug("Loading bean definitions");  
        Element root = doc.getDocumentElement();  

        doRegisterBeanDefinitions(root);  
} 
protected void doRegisterBeanDefinitions(Element root) {  
        <span style="color:#33ff33;">……(注:省略号表示省略掉了代码)  
        //通过代理delegate解析</span>  
        BeanDefinitionParserDelegate parent = this.delegate;  
        this.delegate = createHelper(readerContext, root, parent);  

        preProcessXml(root);  
        parseBeanDefinitions(root, this.delegate);  
        postProcessXml(root);  

        this.delegate = parent;  
}  
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
        if (delegate.isDefaultNamespace(root)) {  
            <span style="color:#33ff33;">//得到xml文件的子节点,比如各个bean节点</span>  
            NodeList nl = root.getChildNodes();  
            <span style="color:#33ff33;">//对每个节点进行分析处理</span>  
            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)) {  
                        <span style="color:#33ff33;">//这里是解析过程的调用,对缺省的元素进行分析比如bean元素</span>  
                        parseDefaultElement(ele, delegate);  
                    }  
                    else {  
                        delegate.parseCustomElement(ele);  
                    }  
                }  
            }  
        }  
        else {  
            delegate.parseCustomElement(root);  
        }  
}  
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
        <span style="color:#33ff33;">//对元素Import进行处理</span>  
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
            importBeanDefinitionResource(ele);  
        }  
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
            processAliasRegistration(ele);  
        }  
        <span style="color:#33ff33;">//对我们熟悉的bean元素进行处理</span>  
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
            processBeanDefinition(ele, delegate);  
        }  
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
            <span style="color:#33ff33;">// recurse</span>  
            doRegisterBeanDefinitions(ele);  
        }  
}  
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
        <span style="color:#33ff33;">//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包括了具体的bean解析过程。把解析bean文件得到的信息放在BeanDefinition里,它是bean信息的主要载体,也是IOC容器的管理对象。</span>  
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  
        if (bdHolder != null) {  
             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
            try {  
                <span style="color:#33ff33;">// Register the final decorated instance.  
                               //向IOC容器注册,实际是放到IOC容器的一个map里</span>         
 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
    }  
    catch (BeanDefinitionStoreException ex) {  
        ……  
    }  
    <span style="color:#33ff33;">// Send registration event.  
    //这里向IOC容器发送事件,表示解析和注册完成</span>  
                    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  

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

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
        <span style="color:#33ff33;">……(省略)</span>  
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
        if (beanDefinition != null) {  
            <span style="color:#33ff33;">//BeanDefinition解析过程</span>  
                                ……(省略)  
            String[] aliasesArray = StringUtils.toStringArray(aliases);  
                           <span style="color:#33ff33;">//将解析完的bean定义包装后返回</span>  
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
        }  
        return null;  
}  
<p> </p>  

在这里对定义文件中的bean元素进行解析,得到AbstractBeanDefinition,并用BeanDefinitionHolder封装后返回。
下面我们看解析完的bean如何在IOC容器中注册:在BeanDefinitionReaderUtils中调用的是:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
throws BeanDefinitionStoreException {  
        <span style="color:#33ff33;">// Register bean definition under primary name.  
        //得到需要注册bean的名字</span>  
        String beanName = definitionHolder.getBeanName();  
        <span style="color:#33ff33;">//调用IOC来注册bean的过程,需要得到BeanDefinition</span>  
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  

        <span style="color:#33ff33;">// Register aliases for bean name, if any.  
        //将别名通过IOC容器和bean联系起来进行注册</span>  
        String[] aliases = definitionHolder.getAliases();  
        if (aliases != null) {  
            for (String aliase : aliases) {  
                registry.registerAlias(beanName, aliase);  
            }  
        }  
}  
接着我们看看bean的注册实现,从上面看到其调用的是BeanDefinitionRegistry的方法registerBeanDefinition完成注册,跟踪代码可知BeanFactory容器的一个实现DefaultListableBeanFactory实现了这个接口并提供了注册的具体实现:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {  

        ......  
        if (beanDefinition instanceof AbstractBeanDefinition) {  
            try {  
                ((AbstractBeanDefinition) beanDefinition).validate();  
            }  
            catch (BeanDefinitionValidationException ex) {  
                <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
                ……  
            }  
        }  

        synchronized (this.beanDefinitionMap) {  
            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
            if (oldBeanDefinition != null) {  
                if (!this.allowBeanDefinitionOverriding) {  
                    <span style="color:#33ff33;">//抛出异常BeanDefinitionStoreException</span>  
                    ……  
                }  
                else {  
                    if (this.logger.isInfoEnabled()) {  
                        ……  
                    }  
                }  
            }  
            else {  
                this.beanDefinitionNames.add(beanName);  
                this.frozenBeanDefinitionNames = null;  
            }  
            this.beanDefinitionMap.put(beanName, beanDefinition);  

            resetBeanDefinition(beanName);  
        }  
}  

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值