• Spring的BeanFactory和FactoryBean


    官方定义

    • BeanFactory:Spring Bean容器的根接口
    • FactoryBean:各个对象的工厂接口,如果bean实现了这个接口,它将被用作对象的工厂,而不是直接作为bean实例。

    源码解析

    BeanFactory

    public interface BeanFactory {
        //标注是获取FactoryBean的实现类,而不是调用getObject()获取的实例
    	String FACTORY_BEAN_PREFIX = "&";
    	Object getBean(String name) throws BeansException;
    	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
    	Object getBean(String name, Object... args) throws BeansException;
    	<T> T getBean(Class<T> requiredType) throws BeansException;
    	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    	boolean containsBean(String name);
    	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    	String[] getAliases(String name);
    }
    

    从源码的方法定义上,就可以看出,BeanFactory作为bean的容器管理器,提供了一系列获取bean以及获取bean属性的方法。

    写一个小例子试验下:

    SimpleBean:

    public class SimpleBean {
        public void send() {
            System.out.println("Hello Spring Bean!");
        }
    }
    

    Spring配置文件config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    						http://www.springframework.org/schema/beans/spring-beans.xsd
    						http://www.springframework.org/schema/context
    						http://www.springframework.org/schema/context/spring-context.xsd">
        <bean id="simpleBean" class="base.SimpleBeanFactoryBean"/>
    </beans>
    

    测试方法:

        public static void main(String[] args) throws Exception {
            ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
            BeanFactory beanFactory = context.getAutowireCapableBeanFactory();
            System.out.println("通过名称获取bean");
            SimpleBean simpleBean = (SimpleBean) beanFactory.getBean("simpleBean");
            simpleBean.send();
            System.out.println("通过名称和类型获取bean");
            simpleBean = beanFactory.getBean("simpleBean", SimpleBean.class);
            simpleBean.send();
            System.out.println("通过类型获取bean");
            simpleBean = beanFactory.getBean(SimpleBean.class);
            simpleBean.send();
            boolean containsBean = beanFactory.containsBean("simpleBean");
            System.out.println("是否包含 simpleBean ? " + containsBean);
            boolean singleton = beanFactory.isSingleton("simpleBean");
            System.out.println("是否是单例? " + singleton);
            boolean match = beanFactory.isTypeMatch("simpleBean", ResolvableType.forClass(SimpleBean.class));
            System.out.println("是否是SimpleBean类型 ? " + match);
            match = beanFactory.isTypeMatch("simpleBean", SimpleBean.class);
            System.out.println("是否是SimpleBean类型 ? " + match);
            Class<?> aClass = beanFactory.getType("simpleBean");
            System.out.println("simpleBean 的类型是 " + aClass.getName());
            String[] aliases = beanFactory.getAliases("simpleBean");
            System.out.println("simpleBean 的别名 : " + Arrays.toString(aliases));
        }
    

    控制台结果:

    通过名称获取bean
    Hello Spring Bean!
    通过名称和类型获取bean
    Hello Spring Bean!
    通过类型获取bean
    Hello Spring Bean!
    是否包含 simpleBean ? true
    是否是单例? true
    是否是SimpleBean类型 ? true
    是否是SimpleBean类型 ? true
    simpleBean 的类型是 base.SimpleBean
    simpleBean 的别名 : []
    

    FactoryBean

    public interface FactoryBean<T> {
        
        /**
         * 获取一个bean,如果配置了工厂bean,在getBean的时候,将会调用此方法,获取一个bean
         */
        T getObject() throws Exception;
    
        /**
         * 获取bean的类型
         */
        Class<?> getObjectType();
    
        /**
         * 是否是单例
         */
        boolean isSingleton();
    
    }
    

    接口是泛型,定义了三个方法,其中getObject()是工厂模式的体现,将会通过此方法返回一个bean的实例。

    一个小例子:

    public class SimpleBeanFactoryBean implements FactoryBean<SimpleBean> {
        @Override
        public SimpleBean getObject() throws Exception {
            System.out.println("MyFactoryBean getObject");
            return new SimpleBean();
        }
    
        @Override
        public Class<?> getObjectType() {
            System.out.println("MyFactoryBean getObjectType");
            return SimpleBean.class;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    

    以上可以修改为单例模式,可以做成线程安全的单例,可塑性较高。

    配置文件config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    						http://www.springframework.org/schema/beans/spring-beans.xsd
    						http://www.springframework.org/schema/context
    						http://www.springframework.org/schema/context/spring-context.xsd">
        <bean id="simple" class="base.SimpleBeanFactoryBean"/>
    </beans>
    

    注意,我们在这里只配置了SimpleBeanFactoryBean,并没有配置SimpleBean,接下来看下getBean方法的输出。

    ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
    SimpleBean simpleBean = context.getBean(SimpleBean.class);
    simpleBean.send();
    

    控制台输出:

    MyFactoryBean getObjectType
    MyFactoryBean getObject
    Hello Spring Bean!
    

    由此我们可以看出FactoryBean的执行流程

    1. 通过getObjectType获取bean的类型
    2. 调用getObject方法获取bean的实例

    总结

    BeanFactoryFactoryBean其实没有关系,只是名称比较像而已。

    • BeanFactory是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范。
    • FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。
  • 相关阅读:
    Insert Buffering
    B-Tree vs LSM-tree
    MySQL 5.6 死锁演示 及 日志分析
    MySQL索引
    InnoDB的三个关键特性
    MySQL如何优化GROUP BY :松散索引扫描 VS 紧凑索引扫描
    MySql 自适应哈希索引
    母牛的故事
    简单的java程序
    一些变量的比较
  • 原文地址:https://www.cnblogs.com/gcdd/p/12292360.html
Copyright © 2020-2023  润新知