一、FactoryBean源码解读
FactoryBean<T> 是 Spring 框架 beans.factory包中的一个接口,从字面意思可以理解为工厂bean,它是干什么的,类名上的泛型又是指什么,有什么作用?
注释看不懂没关系,先看一下它有哪些方法。
public interface FactoryBean<T> {
// 获取实例
@Nullable
T getObject() throws Exception;
// 获取实例的class类型
@Nullable
Class<?> getObjectType();
// 实例默认为单例
default boolean isSingleton() {
return true;
}
}
方法看完了,还是不知道它能干嘛,继续看它的子类。
子类真多,一个屏幕放不下,找几个看看。
二、FactoryBean的子类
先看两个简单的实现类:
1、AuthenticationManagerFactoryBean类
AuthenticationManagerFactoryBean是spring-boot-starter-security 框架中的一个类,这个类实现了FactoryBean<AuthenticationManager>, BeanFactoryAware 两个接口的功能。
BeanFactoryAware 接口在《Spring框架Aware接口的作用和应用》一文中已经介绍过,它是用于在当前类初始化时获取 BeanFactory 接口以供当前类使用的。
FactoryBean<AuthenticationManager>的泛型位置放置了一个类AuthenticationManager。
AuthenticationManagerFactoryBean实现了FactoryBean接口中3个方法
在getObject() 方法中创建了AuthenticationManager实例并返回。
在该方法的最后一行代码可以看出,AuthenticationManager的实例是交给ProviderManager 对象管理的。
因此,在getObjectType()方法中返回的是ProviderManager对象的class。
在 isSingleton()方法中返回的依旧是单例模式。
从以上代码的分析,我们可以得出一个结论,AuthenticationManagerFactoryBean类是用来创建AuthenticationManager对象实例的工厂bean类。
2、CronTriggerFactoryBean类
CronTriggerFactoryBean是Spring框架定时任务 org.springframework.scheduling.quartz 包中的一个类,这个类实现了FactoryBean<CronTrigger>, BeanNameAware, InitializingBean 3个接口的功能。
BeanNameAware 是用于在当前类初始化时获取当前类的bean名称的。
InitializingBean 接口是用于重写初始化方法的。
FactoryBean<CronTrigger>的泛型位置放置了一个类CronTrigger。
CronTrigger是定时任务的表达式对象。
在重写的 afterPropertiesSet() 初始化方法中,new 了一个 CronTriggerImpl对象并返回。
CronTriggerImpl位于定时任务框架 org.quartz中,它是CronTrigger的实现类。
接下来就是FactoryBean三个方法的实现:
getObject() 方法中直接初始化方法中创建的cronTrigger变量。
getObjectType()方法返回的是CronTrigger的class,它是CronTriggerImpl的超类。
isSingleton()方法中返回的是单例模式。
从以上代码的分析,我们也可以得出一个结论,CronTriggerFactoryBean类是用来创建CronTriggerFactory对象实例的工厂bean类。
再来看两个复杂一些的抽象类。
3、AbstractFactoryBean<T>抽象类
AbstractFactoryBean<T>实现了FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean 5个接口。
FactoryBean<T>泛型位置的参数还是泛型。
BeanClassLoaderAware接口是用于在当前类初始化时获取类加载对象ClassLoader的。
BeanFactoryAware接口是用于在当前类初始化时获取BeanFactory的。
InitializingBean 接口是用于重写初始化方法的。
DisposableBean 接口是用于重写销毁方法的。
在初始化方法中,如果是单例则进行实例化:
protected abstract T createInstance() throws Exception;
@Override
@Nullable
public abstract Class<?> getObjectType();
@Override
public final T getObject() throws Exception {
if (isSingleton()) {
return (this.initialized ? this.singletonInstance : getEarlySingletonInstance());
}
else {
return createInstance();
}
}
实例化是个抽象方法,由其子类实现具体实例化逻辑。
getObjectType()也是抽象方法,由其子类实现。
getObject()是个final方法,子类不能更改,如果是单例则返回单例实例,否则每次调用返回一个新的实例。
在AbstractFactoryBean抽象类中,我们最关心的FactoryBean中的2个方法,一个由其子类实现,一个由抽象类实现。不管是子类还是抽象类,目的都是一样的。
4、ListFactoryBean类
ListFactoryBean是AbstractFactoryBean<List<Object>>的子类,通过这个头可以看出它是创建一个List集合的。
在getObjectType()方法中,直接返回List集合的class。
在createInstance()方法中,实现了List集合的实例化逻辑。
还有很多抽象类、实现类,我们就不举例了。
从以上3个类我们可以推断出,FactoryBean就是一个创建和管理bean实例的特殊工厂bean。
FactoryBean的子类很多,但是子接口只有一个,我们也看下。
三、SmartFactoryBean子接口和应用
1、SmartFactoryBean源码解读
SmartFactoryBean接口扩展了FactoryBean接口
public interface SmartFactoryBean<T> extends FactoryBean<T> {
// 是否为原型,默认false
default boolean isPrototype() {
return false;
}
// 是否提前初始化,默认false
default boolean isEagerInit() {
return false;
}
}
这个接口增加了两个方法:
isPrototype()方法,判断当前要创建的bean实例是否是原型。
isEagerInit()方法,判断当前要创建的bean实例是否提前实例化。
2、FactoryBean和SmartFactoryBean的应用比较
1)定义一个bean
public class MyBean2{
public MyBean2() {
System.out.println("1、实例化 MyBean2");
}
public void fun(){
System.out.println("2、调用 MyBean2 的 fun 方法");
}
}
2)把MyBean2对象封装到MyBean2FactoryBean中
@Component
public class MyBean2FactoryBean implements SmartFactoryBean<MyBean2>{
private MyBean2 myBean2;
@Override
public MyBean2 getObject() throws Exception {
if(myBean2 == null){
myBean2 = new MyBean2();
}
return myBean2;
}
@Override
public Class<?> getObjectType() {
return MyBean2.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}
测试FactoryBean接口时,可以把SmartFactoryBean替换成FactoryBean,并把isEagerInit注释掉。
3)测试代码
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
/**
* SmartFactoryBean接口演示代码,是否提前实例化的验证
* @author
* @Description
*
*/
public class SpringApp5 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBean2FactoryBean.class);
MyBean2FactoryBean myBean2FactoryBean = context.getBean(MyBean2FactoryBean.class);
try {
System.out.println("还没有调用呢");
MyBean2 myBean = myBean2FactoryBean.getObject();
myBean.fun();
} catch (Exception e) {
e.printStackTrace();
}
context.close();
}
}
当我们使用 FactoryBean 的时候,Spring 在实例化 Bean 的时候,实例化的是MyBean2FactoryBean 工厂 Bean,MyBean2则是在工厂 Bean中实例化的。
当把工厂bean更改为FactoryBean的时候,运行结果如下:
Creating shared instance of singleton bean 'myBean2FactoryBean'
还没有调用呢
1、实例化 MyBean2
4、调用 MyBean2 的 fun 方法
当把工厂bean更改为SmartFactoryBean的时候,并设置提前实例化时,运行结果如下:
Creating shared instance of singleton bean 'myBean2FactoryBean'
1、实例化 MyBean2
还没有调用呢
4、调用 MyBean2 的 fun 方法
当我们把 isEagerInit() 返回 true时,实例化提前了,没有使用就被实例化了。
最后总结
FactoryBean<T>是一个特殊的bean,用于创建和管理自定义 Bean 实例的工厂bean,其中类名中的泛型就是要创建Bean的类名,如果子类是一个抽象类,那么具体的创建实例过程会延伸到其子类。
FactoryBean<T>定义了一种创建 Bean 的方式,允许在 Bean 的创建过程中进行更多的自定义操作。通过实现 FactoryBean 接口,我们可以创建复杂的 Bean 实例,或者在 Bean 实例化之前进行一些额外的逻辑处理,比如重写初始化方法的InitializingBean等等。
在看源码时,如果看到某个类名是:XxxxFactoryBean,我们就能在瞬间知道这个类是创建Xxxx实例的工厂bean。如果还带有泛型XxxxFactoryBean<T>,就说明这是一个抽象类,具体的创建实例的过程在其子类中。