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方法里面定义了很多 类和配置有环境的 等等