• 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这个容器了。

  • 相关阅读:
    看见一个希腊字母表
    剑桥的技术报告列表
    CompaqDEC的技术报告
    linux动态链接库的使用
    Vectored I/O or ScatterGather I/O
    week reference
    Cache pingpong
    [zz] References on Mutual Excuslion
    redis: event loop
    看WinForm源代码的笔记
  • 原文地址:https://www.cnblogs.com/xiaoblog/p/4267638.html
Copyright © 2020-2023  润新知