zoukankan      html  css  js  c++  java
  • BeanFactory容器的设计原理

    BeanFactory接口提供了使用IOC容器的规范。在这个基础上,Spring还提供了符合这个IOC容器借口了的一系列容器的实现供开发人员使用。先以XmlBeanFactory的实现为例来

    说明简单IOC容器的设计原理,。下图为XmlBeanFactory设计的类继承关系。

    可以看到,作为一个简单IOC容器系列最底层实现的XmlBeanFactory,与我们在Spring应用中用到的上下文相比,有一个明显的特点:它只提供最基本IOC容器的功能。

    我们可以认为直接的BeanFactory实现是IOC容器的基本形式,而各种ApplicationContext的实现是IOC容器的高级表现形式。下面是XmlBeanFactory源码:

     1 public class XmlBeanFactory extends DefaultListableBeanFactory {
     2 
     3     private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
     4 
     5 
     6     /**
     7      * Create a new XmlBeanFactory with the given resource,
     8      * which must be parsable using DOM.
     9      * @param resource XML resource to load bean definitions from
    10      * @throws BeansException in case of loading or parsing errors
    11      */
    12     public XmlBeanFactory(Resource resource) throws BeansException {
    13         this(resource, null);
    14     }
    15 
    16     /**
    17      * Create a new XmlBeanFactory with the given input stream,
    18      * which must be parsable using DOM.
    19      * @param resource XML resource to load bean definitions from
    20      * @param parentBeanFactory parent bean factory
    21      * @throws BeansException in case of loading or parsing errors
    22      */
    23     public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    24         super(parentBeanFactory);
    25         this.reader.loadBeanDefinitions(resource);
    26     }
    27 
    28 }

    XmlBeanFactory继承自DefaultListableBeanFactory这个类,后者很重要,是我们经常要用到的IOC容器的实现,比如在设计应用上下文ApplicationContext时就会用到它。

    在Spring中,实际上是把DefaultListableBeanFactory作为一个默认功能完整的IOC容器来使用的。XmlBeanFactory继承DefaultListableBeanFactory容器功能的同时,增加

    了新的功能。从名字我们可以看出,它是一个与XML相关的BeanFactory,也就是说它是一个可以读取以XML文件方式定义的BeanDefinition的IOC容器。(关于BeanDefinition,我们可以理解为spring ioc的bean配置文件)

    在XmlBeanFactory中,初始化了一个XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML方式定义的BeanDefinition就有了处理的地方。我们可以看到,对这

    些XML形式的信息的处理实际上是由这个XmlBeanDefinitionReader来完成的。

    构造XmlBeanFactory这个IOC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类,下面为Resource源码:

    public interface Resource extends InputStreamSource {
    
        /**
         * Return whether this resource actually exists in physical form.
         * <p>This method performs a definitive existence check, whereas the
         * existence of a {@code Resource} handle only guarantees a
         * valid descriptor handle.
         */
        boolean exists();
    
        /**
         * Return whether the contents of this resource can be read,
         * e.g. via {@link #getInputStream()} or {@link #getFile()}.
         * <p>Will be {@code true} for typical resource descriptors;
         * note that actual content reading may still fail when attempted.
         * However, a value of {@code false} is a definitive indication
         * that the resource content cannot be read.
         * @see #getInputStream()
         */
        boolean isReadable();
    
        /**
         * Return whether this resource represents a handle with an open
         * stream. If true, the InputStream cannot be read multiple times,
         * and must be read and closed to avoid resource leaks.
         * <p>Will be {@code false} for typical resource descriptors.
         */
        boolean isOpen();
    
        /**
         * Return a URL handle for this resource.
         * @throws IOException if the resource cannot be resolved as URL,
         * i.e. if the resource is not available as descriptor
         */
        URL getURL() throws IOException;
    
        /**
         * Return a URI handle for this resource.
         * @throws IOException if the resource cannot be resolved as URI,
         * i.e. if the resource is not available as descriptor
         */
        URI getURI() throws IOException;
    
        /**
         * Return a File handle for this resource.
         * @throws IOException if the resource cannot be resolved as absolute
         * file path, i.e. if the resource is not available in a file system
         */
        File getFile() throws IOException;
    
        /**
         * Determine the content length for this resource.
         * @throws IOException if the resource cannot be resolved
         * (in the file system or as some other known physical resource type)
         */
        long contentLength() throws IOException;
    
        /**
         * Determine the last-modified timestamp for this resource.
         * @throws IOException if the resource cannot be resolved
         * (in the file system or as some other known physical resource type)
         */
        long lastModified() throws IOException;
    
        /**
         * Create a resource relative to this resource.
         * @param relativePath the relative path (relative to this resource)
         * @return the resource handle for the relative resource
         * @throws IOException if the relative resource cannot be determined
         */
        Resource createRelative(String relativePath) throws IOException;
    
        /**
         * Determine a filename for this resource, i.e. typically the last
         * part of the path: for example, "myfile.txt".
         * <p>Returns {@code null} if this type of resource does not
         * have a filename.
         */
        String getFilename();
    
        /**
         * Return a description for this resource,
         * to be used for error output when working with the resource.
         * <p>Implementations are also encouraged to return this value
         * from their {@code toString} method.
         * @see Object#toString()
         */
        String getDescription();
    
    }
    public interface InputStreamSource {
    
        /**
         * Return an {@link InputStream}.
         * <p>It is expected that each call creates a <i>fresh</i> stream.
         * <p>This requirement is particularly important when you consider an API such
         * as JavaMail, which needs to be able to read the stream multiple times when
         * creating mail attachments. For such a use case, it is <i>required</i>
         * that each {@code getInputStream()} call returns a fresh stream.
         * @return the input stream for the underlying resource (must not be {@code null})
         * @throws IOException if the stream could not be opened
         * @see org.springframework.mail.javamail.MimeMessageHelper#addAttachment(String, InputStreamSource)
         */
        InputStream getInputStream() throws IOException;
    
    }

    Resource是Spring用来封装I/O操作的类。比如我们的BeanDefinition信息的以XML文件的形式存在的,那么可以使用像ClassPathResource res = new ClassPathResource

    ("beans.xml")这样具体的ClassPathResource来构造需要的Resource,然后将Resource作为构造参数传递给XmlBeanFactory构造函数。这样,IOC容器就可以方便地定位到

    需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注入过程。

    XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器基础上的,并在这个基本容器的基本上实现了诸如XML读取的附加功能。如代码清单所示,在

    XmlBeanFactory构造方法中需要得到Resource对象。对XmlBeanDefinitionReader初始化,以及使用这个对象来完成loadBeanDefinitions的调用,就是这个调用启动从

    Resource中载人BeanDefinition的过程,loadBeanDefinitions同时也是IOC初始化的重要组成部分。

        public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));
        }
        public EncodedResource(Resource resource) {
            Assert.notNull(resource, "Resource must not be null");
            this.resource = resource;
        }


    我们可以看到XmlBeanFactory使用了DefaultListableBeanFactory作为基类,DefaultListableBeanFactory是很重要的一个IOC实现,在其他IOC容器中,比如ApplicationContext,其实现的基本原理和XmlBeanFactory一样,不过ApplicationContext是继承了其他BeanFactory。

    参考XmlBeanFactory的实现,我们以编程的方式使用DefaultListableBeanFactory。从中我们可以看到IOC容器使用的一些基本过程。尽管应用中我们很少会使用这样的原始

    方式,但了解这个基本过程,对我们了解IOC容器的工作原理是有帮助的。因为这个编程式使用容器的过程,很清楚揭示了在IOC容器实现中的那些关键的类(比如Resource,

    XmlBeanDefinitionReader,DefaultListableBeanFactory)之间的相互关系,例如它们是如何把IOC容器的功能解耦的,又是如何结合在一起为IOC容器服务的,等等。在代码

    清单中我们可以看到编程式使用IOC容器的过程。

           //指定文件
            ClassPathResource res= new ClassPathResource("beans.xml");
            //初始化DefaultListableBeanFactory
            DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
            //初始化构造XmlBeanDefinitionReader
            XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
            //加载BeanDefinition
            reader.loadBeanDefinitions(res)


    这样,我们就可以通过factory对象来使用DefaultListableBeanFactory这个容器了。

  • 相关阅读:
    time 模块学习
    day 14 自定义模块,常用模块 time .datetime ,time 模块
    day 13 课后作业
    day 12 课后作业
    day 11课后作业
    树状数组最值
    hdu 1059 Dividing bitset 多重背包
    XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
    最长公共子序列板/滚动 N^2
    Uva 10635
  • 原文地址:https://www.cnblogs.com/xiaoblog/p/4267638.html
Copyright © 2011-2022 走看看