Spring中FactoryBean的理解与使用

397 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情

前言

Spring知识点中,我们最常听见的就是BeanFactoryFactoryBean这两个词,对Spring熟悉的小伙伴对它们俩肯定是熟捻于心,但是对于没有使用过FactoryBean的新手来说,可能连它是用来干嘛的估计都不知道;今天我们就用这篇文章来简单了解一下FactoryBean

源码分析

我们先来看看FactoryBean长什么样:

import org.springframework.lang.Nullable;
​
public interface FactoryBean<T> {
   String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
​
   @Nullable
   T getObject() throws Exception;
​
   @Nullable
   Class<?> getObjectType();
​
   default boolean isSingleton() {
       return true;
  }
}

原来它是一个接口,里面需要实现两个方法,一个返回T类型对象,一个返回Class类型;我们再去看看它是如何被使用的;下面给小伙伴们找了一个很显著的例子,我们可以看一下MybatisSqlSessionFactoryBean

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBeanApplicationListener<ApplicationEvent> {
 
     public SqlSessionFactory getObject() throws Exception {
       if (this.sqlSessionFactory == null) {
           this.afterPropertiesSet();
      }
       // 返回sqlSessionFactory
       return this.sqlSessionFactory;
  }
 
   // 返回sqlSessionFactory的类型
   public Class<? extends SqlSessionFactory> getObjectType() {
       return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
  }
}

SqlSessionFactoryBeanmybatis中的主要作用就是通过getObject()获取sqlSessionFactory,我们在Spring中通过@Autowired拿到的sqlSessionFactory就是从这里来的;其他的使用案例还有TransactionProxyFactoryBean

public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean implements BeanFactoryAware {
}

主要代码还是在父类AbstractSingletonProxyFactoryBean中:

   public Object getObject() {
       if (this.proxy == null) {
           throw new FactoryBeanNotInitializedException();
      } else {
           return this.proxy;
      }
  }
​
   @Nullable
   public Class<?> getObjectType() {
       if (this.proxy != null) {
           return this.proxy.getClass();
      } else if (this.proxyInterfaces != null && this.proxyInterfaces.length == 1) {
           return this.proxyInterfaces[0];
      } else if (this.target instanceof TargetSource) {
           return ((TargetSource)this.target).getTargetClass();
      } else {
           return this.target != null ? this.target.getClass() : null;
      }
  }

父类中getObject()方法返回的就是代理对象;

从上面两个使用案例中可以发现,FactoryBean就是用来创建Bean对象的,SqlSessionFactoryBean创建的是SqlSessionFactoryTransactionProxyFactoryBean创建的是被代理后的目标对象;

自己实践

为了证实我们自己的想法,我们来自己写一个小案例测试一下:

// 先准备一个实体类
@Data
public class User{
 private String name;
 private int age;
}
​
@Component
public class UserFactoryBean implements FactoryBean<User>,InitializingBean{
 
     private User user;
 
     public void afterPropertiesSet() {
         user = new User();
         user.setName("zouwei");
         user.setAge(26);
    }
 
     public User getObject() {
       return this.user;
    }
 
     public Class<?> getObjectType() {
         return User.class;
    }
}

完成上面两个类的编写后,我们就可以在Spring项目中使用User对象了,我们可以通过@Autowired的方式来获取User对象:

@Autowired
private User user;

虽然我们没有明确把任何User对象交给Spring来管理,但是Spring却可以从UserFactoryBean中拿到它提供的User对象,并且将UserFactoryBeanUser对象一起管理起来;

从上面这个示例中,我们可以更加明确FactoryBeanBeanFactory的区别,其实FactoryBean也是一种动态创建Bean的方式,它是通过getObject()方法来动态创建Bean的,BeanFactory只是一个Bean工厂,专门用来管理Bean的,它们俩是完全不同的两个东西;