FactoryBean
Spring为我们提供了一个接口,用来注入Bean,这就是FactoryBean。
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;
}
}
该接口是一个泛型接口,提供三个方法:
- getObject()方法,返回一个泛型实例,也即我们需要注入的Bean实例。
- getObjectType()方法,返回一个类型。
- isSingleton()方法,是否是单例,即可以对注入的Bean进行设置,是否要以单例形式注入。
自定义FactoryBean
接下来自定义一个FactoryBean,实现FactoryBean接口,并指定需要注入的Bean。
public class MyFactoryBean implements FactoryBean<Phone> {
/**
* 返回一个注入实例
*
* @return
* @throws Exception
*/
@Override
public Phone getObject() throws Exception {
return new Phone();
}
/**
* 指定类型
*
* @return
*/
@Override
public Class<?> getObjectType() {
return Phone.class;
}
/**
* 设置默认以单例形式存在
*
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
主配置类
@Configuration
public class MainConfig {
@Bean
public MyFactoryBean myFactoryBean() {
return new MyFactoryBean();
}
}
编写一个测试方法
@Test
public void testFactoryBean() {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainConfig.class);
Object myFactoryBean = applicationContext.getBean("myFactoryBean");
Object myFactoryBean2 = applicationContext.getBean("myFactoryBean");
System.out.println(myFactoryBean == myFactoryBean2);
}
在测试的时候,因为我们注入的Bean设置为单例,所以在测试方法中两次获取的实例是一样的。
接下来我们打印一下这个Bean,看一下它是什么类型?
System.out.println(myFactoryBean.getClass());
测试打印结果显示
class com.caiyq.spring.annotation.bean.Phone
我们发现,我们从容器中获取到的myFactoryBean类型并不是com.caiyq.spring.annotation.condition.MyFactoryBean,而是class com.caiyq.spring.annotation.bean.Phone,这就说明了,我们需要注入的Phone是通过自定义的MyFactoryBean注入到容器中的。那么MyFactoryBean自己本身的实例,该怎么获取呢?
Object myFactoryBean = applicationContext.getBean("&myFactoryBean");
在通过id获取的时候,在前面加一个&,就可以获取到MyFactoryBean自己本身的实例。看一下BeanFactory接口,就可以明白,在通过getBean获取实例的时候,FactoryBean有一个前缀。
public interface BeanFactory {
/**
* Used to dereference a {@link FactoryBean} instance and distinguish it from
* beans <i>created</i> by the FactoryBean. For example, if the bean named
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
* will return the factory, not the instance returned by the factory.
*/
String FACTORY_BEAN_PREFIX = "&";
}