0
点赞
收藏
分享

微信扫一扫

Spring注解:FactoryBean

闲云困兽 2021-10-15 阅读 97
技术分享
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 = "&";
}
举报

相关推荐

0 条评论