FactoryBean和BeanFactory的区别 spring为何要这么设计FactoryBean的理解(源码地址)

FactoryBean 和BeanFactory

  • FactoryBean 是bean 和其他bean区别不大 而BeanFactory 是一个工厂是用来产生bean的
  • BeanFactory最基本的例子就是spring里面的 AnnotationConfigApplicationContext和 ClassPathXmlApplicationContext
  • FactoryBean 的例子如下

FactoryBean 的介绍

首先说他是一个接口
有三个方法
从文档上可以看出
T getObject() 返回一个对象
Class<?> getObjectType(); 返回他的class对象
default boolean isSingleton() 是不是一个单例

public interface FactoryBean<T> {

	/**
	 * The name of an attribute that can be
	 * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} so that
	 * factory beans can signal their object type when it can't be deduced from
	 * the factory bean class.
	 * @since 5.2
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * <p>As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * <p>If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * <p>This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * <p>In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * <p>This method can be called <i>before</i> this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * <p>The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * <p><b>NOTE:</b> This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * <p>The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 */
	default boolean isSingleton() {
		return true;
	}

FactoryBean的实现类

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Repository;
/*
* 实现了FactroyBean的类 在注入的时候其实是注入了两个bean  一个bean是它本身 另个一个bean 是getObject() 返回的bean
* 使用indexDaoFactoryBean 这个id 取出来的是getObject()返回的bean   使用&indexDaoFactoryBean 取出来的是当前IndexDaoFactoryBean
* */
@Repository()
public class IndexDaoFactoryBean implements FactoryBean {

    String[] ms = {"1","2","3","4"};

    public void query(){
        System.out.println("我是IndexDaoFactoryBean");
    }

    public Object getObject() throws Exception {
        /*
        * 当我们需要依赖注入的bean 需要一些参数或者是依赖第三方bean 我们是不可能把所有的第三方bean 配置维护好 然后注入到我们使用的bean 所以有了
        * FactoryBean  我们通过在注入bean的时候吧所有的第三方依赖配置好 使我们可以直接使用 需要的bean和他依赖的第三方配置关系 所以我们会在  getObject() 也就是
        * 当前方法里面 配置好所需要的依赖第三方bean 和配置文件  都配置好了 返回给spring容器
        * 详细使用参考mybatis
        * 配置selsessionFactoryBean 就是一个经典案例
        * */
        TestDaoImpl testDao =  new TestDaoImpl();
        testDao.setM1(ms[0]);
        testDao.setM2(ms[1]);
        testDao.setM3(ms[2]);
        testDao.setM4(ms[3]);
        return testDao;
    }

    public Class<?> getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }
}

FactoryBean getObject返回的类

package yongli.dao.Impl;

public class TestDaoImpl implements yongli.dao.TestDao {

    String m1;

    String m2;

    String m3;

    String m4;


    public String getM1() {
        return m1;
    }

    public void setM1(String m1) {
        this.m1 = m1;
    }

    public String getM2() {
        return m2;
    }

    public void setM2(String m2) {
        this.m2 = m2;
    }

    public String getM3() {
        return m3;
    }

    public void setM3(String m3) {
        this.m3 = m3;
    }

    public String getM4() {
        return m4;
    }

    public void setM4(String m4) {
        this.m4 = m4;
    }

    public void query() {
        System.out.println("我是testDao"+m1+m2+m3+m4);
    }
}

测试类运行

public class testFactoryBean {
/*
*IndexDaoFactoryBean 类里面有注释
* */
    public static void  main(String[]args){

        //取出 getObject()里面的bean
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class);
        TestDaoImpl testDao = (TestDaoImpl) annotationConfigApplicationContext.getBean("indexDaoFactoryBean");
        testDao.query();

        //取出IndexDaoFactoryBean本身
        IndexDaoFactoryBean indexDaoFactoryBean= (IndexDaoFactoryBean) annotationConfigApplicationContext.getBean("&indexDaoFactoryBean");
        indexDaoFactoryBean.query();

    }
}

运行结果

在这里插入图片描述
可以明显看到 indexDaoFactoryBean 取出的是我们getObject()里面自己实现的bean 而 使用 &indexDaoFactoryBean 取出来是我们原来注册的bean 这里引申出一个问题他为啥这样实现呢?

为何使用FactoryBean

首先我们注册一个bean 要是他有依赖我们会 在xml里面

<beans>
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg ref="beanTwo"/>
        <constructor-arg ref="beanThree"/>
    </bean>

    <bean id="beanTwo" class="x.y.ThingTwo"/>

    <bean id="beanThree" class="x.y.ThingThree"/>
</beans>

就想这样需要ref指向 但是有个很恐怖的问题 就是 如果 ref指向的bean还有依赖呢 依赖的bean还有配置并且还有依赖呢呢这样想想我们会因为一个bean会引申出很多的bean 就算你不闲麻烦一个个配置好了每个bean 但是有些bean是第三方的 依赖的 我们无法去了解到他们如何配置 去如何加载 或者说你根本无法创建这个bean只能内部创建呢?结构图由mybatis为例子
在这里插入图片描述
图上面绿色的为我们需要维护的 导入spring依赖配置spring文件等等由我们维护 spring依赖mybatis 问题来了mybatis害依赖着第三方 我们不可能去维护 紫色框里面所需要的的类 我们只能交给mybatis去维护 因此出现了FacoryBean 我们要的是配置好的bean
所以很多的配置都在getObject这个方法里面配置好 我们拿到的是维护好的 bean
mybatis官网例子
在这里插入图片描述
在这里插入图片描述
可以看到我们sqlsessionFactory 在getObject方法里面定义了很多 类和配置有环境的 等等

dome源码地址点击这里

猜你喜欢

转载自blog.csdn.net/weixin_43979902/article/details/120529423
今日推荐