欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用FactoryBean接口实现自定义bean初始化

程序员文章站 2022-03-03 12:33:06
...

使用FactoryBean接口实现自定义bean初始化

 

       本文所要介绍的FactoryBeanSpring中定义的一个接口,当把它的实现类定义为BeanFactory中的一个bean,我们在获取其对应的bean时实际上获取的是FactoryBean所包含的那个对象,而不是它本身。我们先来看一下FactoryBean的定义。

public interface FactoryBean<T> {
 
   /**
    * 获取实际要返回的bean对象。
    * @return
    * @throws Exception
    */
   T getObject() throws Exception;
 
   /**
    * 获取返回的对象类型
    * @return
    */
   Class<?> getObjectType();
 
   /**
    * 是否单例
    * @return
    */
   boolean isSingleton();
 
}

 

 

       我们可以看到FactoryBean是使用了泛型的,表示其对应产生的Bean是什么类型的对象。我们来看一个实现。

public class UserFactoryBean implements FactoryBean<User> {
 
   private User user;
 
   @Override
   public User getObject() throws Exception {
      if (user == null) {
         synchronized (this) {
            if (user == null) {
                User user = new User();
                user.setId(1);
                user.setName("张三");
                this.user = user;
            }
         }
      }
      returnuser;
   }
 
   @Override
   public Class<?> getObjectType() {
      return User.class;
   }
 
   @Override
   public boolean isSingleton() {
      return true;
   }
  
}

 

 

       上面代码中定义了一个UserFactoryBean,用以产生一个单例的User对象。可以看到,我们在getObject()方法中使用了同步块来保证产生的bean永远是同一个对象。其实这个并不是必须的。在初始化时BeanFactory调用FactoryBean创建bean时就是同步的,而且BeanFactory创建bean时默认是单例的,也就意味着FactoryBeangetObject方法在BeanFactory中定义为单例的时候只会调用一次。但有一种情况例外,那就是如果定义bean时指定了“lazy-init=true”时,那就意味着该bean只有在用到的时候才会进行初始化,这个时候如果刚好两个线程同时需要使用,就会出现在两个线程中同时调用FactoryBeangetObject方法进行bean的初始化,如不加控制就会出现两个实例。为保证只有一个实例,getObject方法内部需要是同步的。

       此外,需要注意的是FactoryBeanisSingleton方法返回结果表示当前FactoryBean产生的bean是否是单例形式,即每次请求getObject()方法返回的是否都是同一个bean对象。其实FactoryBean更多的是在Spring内部使用,isSingleton只是用来表示当前返回的bean对象是否可以用BeanFactory缓存的一个标志。

       上面示例对象的Spring配置文件如下:

       <bean id="userFactoryBean" class="com.xxx.spring.factorybean.UserFactoryBean" lazy-init="false"/>

 

       对于一个FactoryBean接口实现类定义的bean其实Spring将实例化两个bean,一个是FactoryBean本身对应的bean,另一个是FactoryBean产生的对象对应的bean。所以当我们在通过注解方式注入一个FactoryBean实例对应的bean时,既可以把它当做一个FactoryBean进行注入,也可以把它当做一个对应产生的实例进行注入。而如果是自己直接从ApplicationContext中获取的话,则直接通过FactoryBean实现类定义的bean名称获取到的是FactoryBean实现类产生的对象。如在上面示例中,如果我们通过ApplicationContextgetBean(“userFactoryBean”)获取到的就将是对应产生的User对象,如果我们需要获取到对应的FactoryBean本身,则可以在对应的FactoryBean实现类定义的bean名称前加上“&”进行获取,如上如果我们要获取到UserFactoryBean本身,则可以通过ApplicationContextgetBean(“&userFactoryBean”)。如果是通过类型获取,就可以直接通过User类型或者UserFactoryBean类型获取到对应的bean对象了。

 

(注:本文是基于Spring3.1.0所写)