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

使用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所写)

 

 

 

 

 

 

 

 

猜你喜欢

转载自elim.iteye.com/blog/2074583