Spring源码 BeanFactory和FactoryBean是什么?

Posted 有一只柴犬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码 BeanFactory和FactoryBean是什么?相关的知识,希望对你有一定的参考价值。

1、前言

面试官:“看过Spring源码吧,简单说说Spring中BeanFactory和FactoryBean的区别是什么?”

大神仙:“BeanFactory是bean工厂,FactoryBean是工厂bean”。

这么回答,等于面试官问你Spring是什么,你回答这个单词翻译叫春天。

2、ChitGPT的回答

首先看下C知道(ChitGPT)的回答

没错,基本上已经给出了答案。

那么接下来,我们来详细看下他们分别是什么。

3、什么是BeanFactory?

其实BeanFactory回答是bean工厂也没毛病,确实是。但是却没回答到本质。

我们知道,Spring其中一个核心功能就是IoC。Spring创建bean,使用的是经典的工厂模式,那么这一系列的bean工厂,就是IoC容器或称为对象工厂。

我们先来看下Spring源码中对于BeanFactory的注释:

/**
 * // 访问Spring bean容器的根接口
 * The root interface for accessing a Spring bean container.
 *
 * ......
 *
 * // 这个接口是由拥有许多bean定义的对象实现的,每个bean定义都由一个String名称唯一标识。
 * // 根据bean定义,工厂将返回包含对象的独立实例(原型设计模式),或者返回单个共享实例(单例设计模式的高级替代方案,在单例设计模式中,
 * // 实例在工厂范围内是单例)。将返回哪种类型的实例取决于bean工厂配置。
 * <p>This interface is implemented by objects that hold a number of bean definitions,
 * each uniquely identified by a String name. Depending on the bean definition,
 * the factory will return either an independent instance of a contained object
 * (the Prototype design pattern), or a single shared instance (a superior
 * alternative to the Singleton design pattern, in which the instance is a
 * singleton in the scope of the factory). Which type of instance will be returned
 * depends on the bean factory configuration: the API is the same. Since Spring
 * 2.0, further scopes are available depending on the concrete application
 * context (e.g. "request" and "session" scopes in a web environment).
 *
 * ......
 * 
 * // 通常,BeanFactory将加载存储在配置源(如XML文档)中的bean定义,并使用@code org.springframework。Beans包来配置bean。
 * // 但是,实现可以直接在Java代码中返回它根据需要创建的Java对象。对于如何存储定义没有限制:LDAP、RDBMS、XML、属性文件等等。
 * // 鼓励实现支持bean之间的引用(依赖注入)。
 * <p>Normally a BeanFactory will load bean definitions stored in a configuration
 * source (such as an XML document), and use the @code org.springframework.beans
 * package to configure the beans. However, an implementation could simply return
 * Java objects it creates as necessary directly in Java code. There are no
 * constraints on how the definitions could be stored: LDAP, RDBMS, XML,
 * properties file, etc. Implementations are encouraged to support references
 * amongst beans (Dependency Injection).
 *
 * ......
 * // Bean工厂实现应该尽可能支持标准的Bean生命周期接口。完整的初始化方法集及其标准顺序为:
 * <p>Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:
 * <ol>
 * <li>BeanNameAware's @code setBeanName
 * <li>BeanClassLoaderAware's @code setBeanClassLoader
 * <li>BeanFactoryAware's @code setBeanFactory
 * <li>EnvironmentAware's @code setEnvironment
 * <li>EmbeddedValueResolverAware's @code setEmbeddedValueResolver
 * <li>ResourceLoaderAware's @code setResourceLoader
 * (only applicable when running in an application context)
 * <li>ApplicationEventPublisherAware's @code setApplicationEventPublisher
 * (only applicable when running in an application context)
 * <li>MessageSourceAware's @code setMessageSource
 * (only applicable when running in an application context)
 * <li>ApplicationContextAware's @code setApplicationContext
 * (only applicable when running in an application context)
 * <li>ServletContextAware's @code setServletContext
 * (only applicable when running in a web application context)
 * <li>@code postProcessBeforeInitialization methods of BeanPostProcessors
 * <li>InitializingBean's @code afterPropertiesSet
 * <li>a custom @code init-method definition
 * <li>@code postProcessAfterInitialization methods of BeanPostProcessors
 * </ol>
 *
 * <p>On shutdown of a bean factory, the following lifecycle methods apply:
 * <ol>
 * <li>@code postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
 * <li>DisposableBean's @code destroy
 * <li>a custom @code destroy-method definition
 * </ol>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 13 April 2001
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.EnvironmentAware#setEnvironment
 * @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 */
public interface BeanFactory 
    ......

可以看到,BeanFactory是一个接口类,且是最顶层的一个接口类,其中定义了IoC容器的基本功能规范,用来更好的管理(或者说约束)实现类对于bean的管理,如实例化,定位,配置对应以及创建对象间依赖等。

BeanFactory有三个比较重要的接口子类:AutowireCapableBeanFactory,ListableBeanFactory,HierarchicalBeanFactory。BeanFactory有一个默认的实现类是DefaultListableBeanFactory。

在Spring中,DefaultListableBeanFactory被作为一个默认的IoC容器来使用。

来看下类图:

简化一下:

  • AutowireCapableBeanFactory:表示Bean的自动装配规则
  • ListableBeanFactory:表示Bean可列表化
  • HierarchicalBeanFactory:表示Bean有继承关系

这三个接口共同定义了Bean的集合,Bean之间的关系,以及Bean的行为。而BeanFactory是IoC容器最基本的接口类。

再来看下BeanFactory源码内容:

public interface BeanFactory 

   // 对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,
   // 如果需要得到工厂本身,需要转义
    String FACTORY_BEAN_PREFIX = "&";
    
    // 根据bean的名字,获取在IOC容器中得到bean实例
    Object getBean(String var1) throws BeansException;
    
    // 根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。
    <T> T getBean(String var1, Class<T> var2) throws BeansException;
    Object getBean(String var1, Object... var2) throws BeansException;
    <T> T getBean(Class<T> var1) throws BeansException;
    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    // 提供对bean的检索,看看是否在IOC容器有这个名字的bean
    boolean containsBean(String var1);

    // 根据bean名字得到bean实例,并同时判断这个bean是不是单例
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    // 得到bean实例的Class类型
    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    // 得到bean的别名,如果根据别名检索,那么其原名也会被检索出来
    String[] getAliases(String var1);

在BeanFactory中只对IoC容器的基本行为做了定义,通过实现该接口可以实现不同的Bean检索方法。在Spring中也提供了许多IoC容器的实现,如GenericApplicationContext,ClassPathXmlApplicationContext等。

但是在Spring中,是不允许我们直接使用BeanFactory的,他给我们提供了ApplicationContext接口继承BeanFactory接口,同时进行了很多扩展:如实现国际化(实现MessageSource接口),访问资源(实现ResourcePatternResolver接口),支持应用事件(实现ApplicationEventPublisher接口)。

以下为ApplicationContext子类继承图:

4、什么是FactoryBean?

FactoryBean是一个工厂Bean。也是一个接口,该接口提供了一个工厂方法,用来返回其他Bean实例。

来看下注释:

/**
 * // 由@link BeanFactory中使用的对象实现的接口,这些对象本身就是单个对象的工厂。
 * // 如果一个bean实现了这个接口,那么它将被用作要公开的对象的工厂,而不是直接用作将自己公开的bean实例。
 * Interface to be implemented by objects used within a @link BeanFactory which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * // 注意:实现该接口的bean不能作为普通bean使用。
 * // FactoryBean是以bean风格定义的,但是为bean引用公开的对象(@link #getObject())始终是它创建的对象。
 * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references (@link #getObject()) is always the object that it creates.
 * ......
 *
 * // 该接口在框架本身中被大量使用,例如用于AOP @link org.springframework.jndi.JndiObjectFactoryBean。
 * // 它也可以用于定制组件;但是,这只在基础结构代码中常见。
 * <p>This interface is heavily used within the framework itself, for example for
 * the AOP @link org.springframework.aop.framework.ProxyFactoryBean or the
 * @link org.springframework.jndi.JndiObjectFactoryBean. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 * ......
 *
 * // 最后,FactoryBean对象参与了包含BeanFactory的bean创建的同步。
 * // 除了在FactoryBean本身(或类似)内进行惰性初始化之外,通常不需要内部同步。
 * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param <T> the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */
public interface FactoryBean<T> 
    ......

但从官方给的注释上也能看出,FactoryBean其实就是个Bean,是在IoC容器的基础上给Bean的实现加上了一个简单的工厂模式和装饰模式,是一个用于生产Bean对象的工厂Bean。用户通过实现该接口,可以通过getObject()方法获取对象。

public interface FactoryBean<T> 

   // 获取容器管理的对象实例
   @Nullable
   T getObject() throws Exception;

   // 获取Bean工厂创建的对象类型
   @Nullable
   Class<?> getObjectType();

   // Bean工厂创建的对象是否单例模式,
   // 如果是,则整个容器中只有一个实例对象,每次请求都返回同一个实例对象
   default boolean isSingleton() 
      return true;
   

5、小结

BeanFactory:

  • 是所有Spring中IoC容器的顶级接口,为Spring的容器定义了一套规范,并提供像getBean()方法从容器中获取Bean实例;
  • 负责生产和管理Bean的一个工厂;
  • 在产生Bean实例的同时,还提供了DI的能力;

FactoryBean:

  • 实际上就是个bean,相当于普通的Bean的实现加上了简单工厂模式和装饰模式;
  • 动态生成某一个类别的Bean实例;
  • getObject() 获取的是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,需要在id前加一个&;

Spring源码试读--BeanFactory模拟实现

动机

现在Springboot越来越便捷,如果简单的Spring应用,已无需再配置xml文件,基本可以实现全注解,即使是SpringCloud的那套东西,也都可以通过yaml配置完成。最近一年一直在用Springboot+JPA或者Springboot+MyBatis,基本上不用Spring和SpringMVC了,心血来潮想着趁国庆假期试着一点点实现一下Spring的基本功能(当然是会对照源码的,毕竟很多细节想不到,变量命名也会按照源码来),基本思路就是先按照Spring的类图试着自己写,争取实现相同的功能,然后再看源码的实现方式,再重构。

第一篇先实现Spring的基本组件--bean容器

雏形

定义两个接口BeanFactory和BeanDefinition

public interface BeanFactory {

    BeanDefinition getBeanDefinition(String beanID)
    Object getBean(String beanID);
}
public interface BeanDefinition {

    public String getBeanClassName();
}

两个实现类DefaultBeanFactory和GenericBeanDefinition分别实现这两个接口:


public class DefaultBeanFactory implements BeanFactory {
    public static final String ID_ATTRIBUTE="id";
    public static final String CLASS_ATTRIBUTE="class";
    private Map<String,BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<String, BeanDefinition>();
    public DefaultBeanFactory(String configFile) {
        loadBeanDefinition(configFile);

    }
    
    private void loadBeanDefinition(String configFile) {
        InputStream is= null;
        ClassLoader classLoader = this.getClass().getClassLoader();
        is=classLoader.getResourceAsStream(configFile);
        //需要dom4j
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(is);
            Element root = doc.getRootElement();
            Iterator iterator = root.elementIterator();
            while (iterator.hasNext()){
                Element element = (Element)iterator.next();
                String id=element.attributeValue(ID_ATTRIBUTE);
                String className=element.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition beanDefinition = new GenericBeanDefinition(id, className);
                beanDefinitionMap.put(id,beanDefinition);
            }
        } catch (DocumentException e) {
           throw new BeanDefinitionStoreException("Load and parsing XML failed",new Throwable());
        }finally {
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }



    }

    public BeanDefinition getBeanDefinition(String beanID) {
        if(beanDefinitionMap.containsKey(beanID))
            return beanDefinitionMap.get(beanID);
        return null;
    }
    //职责2:创建bean实例
    public Object getBean(String beanID) {
        BeanDefinition beanDefinition = this.getBeanDefinition(beanID);
        if(beanDefinition==null){
            throw new BeanCreationException("Bean Definition does not exist");
        }
        ClassLoader classLoader = this.getClass().getClassLoader();
        try {
            Class<?> clz = classLoader.loadClass(beanDefinition.getBeanClassName());
            return clz.newInstance();
            //捕获所有异常,然后抛出自定义异常
        } catch (Exception e) {
            throw new BeanCreationException("create bean for "+beanDefinition.getBeanClassName()+" failed.");
        }

    }
}
public class GenericBeanDefinition implements BeanDefinition {
    private String id;
    private String beanClassName;
    public GenericBeanDefinition(String id, String beanClassName) {
        this.id = id;
        this.beanClassName = beanClassName;
    }
    public String getBeanClassName() {

        return this.beanClassName;
    }

}

主要逻辑在DefaultBeanFactory中,通过解析xml来生成一个bean实例并保存到Map中。

单一指责原则

  • 核心思想:一个类应该有且只有一个变化的原因。

  • 为什么引入单一职责:

    在SRP中,把职责定义为变化的原因。当需求变化时,将通过更改职责相关的类来体现。如果一个类拥有多于一个的职责,则多个职责耦合在一起,会有多于一个原因来导致这个类发生变化。一个职责的变化可能会影响到其他的职责,另外,把多个职责耦合在一起,影响复用性。如:DefaultBeanFactory类目前有两个指责:1.加载和读取XML文件;2.创建bean实例

    我们把读取XML的职责拆分出来给一个新类XMLBeanDefinitionReader,同时,BeanFactory是供给client使用的,而BeanDefinition是一个内部的概念,应该对client是透明的,所以不应该对外暴露,所以把getBeanDefinition和注册(即之前的添加到Map)职责分出来给一个新接口BeanDefinitionRegistry。DefaultBeanFactory实现BeanDefinitionRegistry,下一节会用一个ApplicationContext包装DefaultBeanFactory,进而对用户屏蔽getBeanDefinition()和registerBeanDefinition()。

技术图片

修改后的DefaultBeanFactory

public class DefaultBeanFactory implements BeanFactory,BeanDefinitionRegistry {
    private Map<String,BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<String, BeanDefinition>();
    public DefaultBeanFactory(){

    }

    public BeanDefinition getBeanDefinition(String beanID) {
        if(beanDefinitionMap.containsKey(beanID))
            return beanDefinitionMap.get(beanID);
        return null;
    }

    public void registerBeanDefinition(String beanID, BeanDefinition beanDefinition) {
        this.beanDefinitionMap.put(beanID,beanDefinition);
    }


    public Object getBean(String beanID) {
        BeanDefinition beanDefinition = this.getBeanDefinition(beanID);
        if(beanDefinition==null){
            throw new BeanCreationException("Bean Definition does not exist");
        }
        ClassLoader classLoader = this.getClass().getClassLoader();
        try {
            Class<?> clz = classLoader.loadClass(beanDefinition.getBeanClassName());
            return clz.newInstance();
            //捕获所有异常,然后抛出自定义异常
        } catch (Exception e) {
            throw new BeanCreationException("create bean for "+beanDefinition.getBeanClassName()+" failed.");
        }

    }
}

BeanDefinitionRegistry接口:

public interface BeanDefinitionRegistry {
    BeanDefinition getBeanDefinition(String beanID);
    void registerBeanDefinition(String beanID,BeanDefinition beanDefinition);
}

XmlBeanDefinitionReader类:用来读取XML并调用BeanDefinitionRegistry的registerBeanDefinition方法注册beanDefinition。

public class XmlBeanDefinitionReader {

    public static final String ID_ATTRIBUTE = "id";

    public static final String CLASS_ATTRIBUTE = "class";

    public static final String SCOPE_ATTRIBUTE = "scope";

    BeanDefinitionRegistry registry;

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void loadBeanDefinition(String configFile) {
        InputStream is = null;
        ClassLoader classLoader = this.getClass().getClassLoader();
        is = classLoader.getResourceAsStream(configFile);
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(is);
            Element root = doc.getRootElement();
            Iterator iterator = root.elementIterator();
            while (iterator.hasNext()) {
                Element element = (Element) iterator.next();
                String id = element.attributeValue(ID_ATTRIBUTE);
                String className = element.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition beanDefinition = new GenericBeanDefinition(id, className);
                registry.registerBeanDefinition(id, beanDefinition);
            }
        } catch (DocumentException e) {
            throw new BeanDefinitionStoreException("Load and parsing XML failed", new Throwable());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

ApplicationContext

Spring中通常不会直接访问BeanFactory,而是通过ApplicationContext来得到bean,即通过ApplicationContext调用BeanFactory方法。

技术图片

定义一个接口ApplicationContext继承BeanFactory:

public interface ApplicationContext extends BeanFactory {
}

创建一个实现类ClassPathXmlApplicationContext,从ClassPath下读取XML,内部持有一个DefaultBeanFactory实例,对外只暴露getBean()方法,屏蔽了getBeanDefinition()和registerBeanDefinition():

public class ClassPathXmlApplicationContext implements ApplicationContext {
    private DefaultBeanFactory factory=null;
    public ClassPathXmlApplicationContext(String configFile) {
        factory=new DefaultBeanFactory();
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinition(configFile);
    }

    public Object getBean(String beanID) {
        return factory.getBean(beanID);
    }
}

Resource

使用Resource来抽象资源

技术图片

除了从ClassPath读取XML,还可以从FileSystem读取,最终都是要转换成为一个InputStream,所以抽象出一个Resource接口,并创建两个实现类来分别处理从两种途径读取XML。


public interface Resource {
    InputStream getInputStream() throws IOException;
    String getDescription();

}
public class ClassPathResource implements Resource {

    private String path;
    private ClassLoader classLoader;

    public ClassPathResource(String path) {
        this(path, (ClassLoader) null);
    }
    public ClassPathResource(String path, ClassLoader classLoader) {
        this.path = path;
        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }

    public InputStream getInputStream() throws IOException {
        InputStream is = this.classLoader.getResourceAsStream(this.path);

        if (is == null) {
            throw new FileNotFoundException(path + " cannot be opened");
        }
        return is;

    }
    public String getDescription(){
        return this.path;
    }

}
public class FileSystemResource implements Resource {

    private final String path;
    private final File file;


    public FileSystemResource(String path) {
        //这里的Assert不是junit的Assert,是自定义的一个工具类,就是判空处理并提示指定信息,逻辑简单不贴代码了
        Assert.notNull(path, "Path must not be null");
        this.file = new File(path);
        this.path = path;
    }

    public InputStream getInputStream() throws IOException {
        return new FileInputStream(this.file);
    }

    public String getDescription() {
        return "file [" + this.file.getAbsolutePath() + "]";
    }

}

现在DefaultBeanFactory中的loadBeanDefinition可以接收一个Resource对象,从中获取InputStream,而不用管是从classpath还是从FileSystem读取的。同时可以创建一个与ClassPathXmlApplicationContext相对应的FileSystemXmlApplicationContext类来完成从FileSystem读取XML并获取bean:

public class FileSystemXmlApplicationContext implements ApplicationContext {
    DefaultBeanFactory factory=null;
    public FileSystemXmlApplicationContext(String path) {
        factory=new DefaultBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        //这是与ClassPathXmlApplicationContext唯一的区别
        Resource resource=new FileSystemResource(path);
        reader.loadBeanDefinition(resource);
    }
    public Object getBean(String beanID){
        return factory.getBean(beanID);

    }
}

可以发现这个类和ClassPathXmlApplicationContext唯一的区别就是Resource不同,为了避免重复代码,用模板方法重构,新建一个抽象类AbstractApplicationContext,然后两个ApplicationContext类继承并实现getResourceByPath。

public abstract class AbstractApplicationContext implements ApplicationContext {

    private DefaultBeanFactory factory = null;
    private ClassLoader beanClassLoader=null;

    public AbstractApplicationContext(String configFile){
        factory = new DefaultBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        Resource resource = this.getResourceByPath(configFile);
        reader.loadBeanDefinition(resource);
    }

    public Object getBean(String beanID) {

        return factory.getBean(beanID);
    }

    protected abstract Resource getResourceByPath(String path);
}

Scope

Spring中的bean有一个scope属性用来指定bean是否是单例。而Spring是如何管理单例对象的呢?肯定不是把类设计成单例模式,而是Spring统一管理bean,然后根据scope属性来提供bean实例。

先定义一个接口SingletonBeanRegistry:

public interface SingletonBeanRegistry {

    void registerSingleton(String beanName, Object singletonObject);

    Object getSingleton(String beanName);
}

它的实现类DefaultSingletonBeanRegistry,通过一个Map管理单例对象:

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

    public void registerSingleton(String beanName, Object singletonObject) {

        Assert.notNull(beanName, "‘beanName‘ must not be null");

        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null) {
            throw new IllegalStateException("Could not register object [" + singletonObject +
                    "] under bean name ‘" + beanName + "‘: there is already object [" + oldObject + "] bound");
        }
        this.singletonObjects.put(beanName, singletonObject);

    }

    public Object getSingleton(String beanName) {

        return this.singletonObjects.get(beanName);
    }

}

咱们的DefaultBeanFactory要继承DefaultSingletonBeanRegistry(也可以内部持有一个DefaultSingletonBeanRegistry对象,采用组合模式),修改getBean()方法:

public Object getBean(String beanID) {
    BeanDefinition beanDefinition = this.getBeanDefinition(beanID);
    if(beanDefinition==null){
        throw new BeanCreationException("Bean Definition does not exist");
    }
    if(beanDefinition.isSingleton()){
        Object bean = this.getSingleton(beanID);
        if(bean == null){
            bean = createBean(beanDefinition);
            this.registerSingleton(beanID, bean);
        }
        return bean;
    }
    return createBean(beanDefinition);



}

同时我们的BeanDefinition和GenericBeanDefinition也要修改,增加Singleton相关的属性:

public interface BeanDefinition {
    public static final String SCOPE_SINGLETON = "singleton";
    public static final String SCOPE_PROTOTYPE = "prototype";
    public static final String SCOPE_DEFAULT = "";

    public boolean isSingleton();
    public boolean isPrototype();
    String getScope();
    void setScope(String scope);

    public String getBeanClassName();
}
public class GenericBeanDefinition implements BeanDefinition {
    private String id;
    private String beanClassName;
    private boolean singleton = true;
    private boolean prototype = false;
    private String scope = SCOPE_DEFAULT;
    public GenericBeanDefinition(String id, String beanClassName) {

        this.id = id;
        this.beanClassName = beanClassName;
    }
    public String getBeanClassName() {

        return this.beanClassName;
    }

    public boolean isSingleton() {
        return this.singleton;
    }
    public boolean isPrototype() {
        return this.prototype;
    }
    public String getScope() {
        return this.scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
        this.singleton = SCOPE_SINGLETON.equals(scope) || SCOPE_DEFAULT.equals(scope);
        this.prototype = SCOPE_PROTOTYPE.equals(scope);

    }
}

XmlBeanDefinitionReader类中的loadBeanDefinition()也要修改,使其能读取XML文件中的scope属性。

至此,基本的BeanFactory就实现了。我们可以通过Xml文件装载Bean了。

以上是关于Spring源码 BeanFactory和FactoryBean是什么?的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

Spring源码解析 - BeanFactory

Spring源码试读--BeanFactory模拟实现

Dubbo源码学习ScopeBeanFactory对比Spring 的BeanFactory

Spring BeanFactory源码学习