spring源码学习笔记(二)FactoryBean的使用和源码解析
每天多学一点点~
话不多说,这就开始吧…
1.前言
BeanFactory和FactoryBean的区别?之前一直有点迷迷糊糊,最近重看spring源码,遂研究记录一下。
先说结论:
- BeanFactory是Bean的工厂,Spring的顶层核心接口。没有BeanFactory就没有Bean的存在,工厂只负责按照要求生产Bean。Bean的定义信息,要生产成什么样由ApplicationContext说了算。ApplicationContext面向的是用户,所以需要更好地服务用户,不仅要提供Bean和调用工厂去生产Bean,还要提供一系列人性化的服务(如国际化,加载Bean定义、监听等),怎么生成Bean的事交给工厂去做。
- Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean,这两种Bean都被容器管理,但工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象。在Spring框架内部,有很多地方有FactoryBean的实现类,它们在很多应用如(Spring的AOP、ORM、事务管理)及与其它第三框架(hibernate、mybatis、jpa…)集成时都有体现。后面有机会再谢谢mybatis是如何偷天换日集成spring的。
2. FactoryBean示例
FactoryBean 接口,被他修饰的Bean将成为一个特殊的bean,原本的bean将被隐藏,而是由FactoryBean的getObject返回最终的bean。可以简单的把FactoryBean当做是一个改装车行,可以改成你原本的bean。比如下面这个示例:
- Config 类
@Configuration
@ComponentScan("com.zjq.factorybeantest")
public class Config {
}
- MyService类
@Service("myService")
public class MyService {
public void getUser() {
System.out.println(" 调用 MyService getUser 方法");
}
}
- MyFactoryBean 类
@Component
public class MyFactoryBean implements FactoryBean<MyService> {
@Override
public MyService getObject() throws Exception {
System.out.println("调用 MyFactoryBean getObject ");
return new MyService();
}
@Override
public Class<?> getObjectType() {
System.out.println("调用 MyFactoryBean getObjectType ");
// FactoryBean所产生的Bean的类型
return MyService.class;
}
@Override
public boolean isSingleton() {
System.out.println("调用 MyFactoryBean isSingleton ");
// 设置返回的Bean是否为单例
return true;
}
}
- 调用类
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
System.out.println("==============================");
MyService bean0 = (MyService) context.getBean("myService");
bean0.getUser();
System.out.println("myService bean0 : " + bean0.getClass());
System.out.println("==============================");
// 返回的是 class com.zjq.factorybeantest.MyService 返回的是getObject()
Object bean1 = context.getBean("myFactoryBean");
System.out.println("bean1 bean :" + bean1.getClass());
System.out.println("==============================");
// 返回的是 class com.zjq.factorybeantest.MyFactoryBean
Object bean2 = context.getBean("&myFactoryBean");
System.out.println("bean2 bean : " + bean2.getClass());
}
打印结果:
调用 MyFactoryBean getObjectType
调用 MyFactoryBean getObjectType
调用 MyFactoryBean getObjectType
调用 MyFactoryBean isSingleton
调用 MyFactoryBean getObjectType
==============================
调用 MyService getUser 方法
myService bean : class com.zjq.factorybeantest.MyService
==============================
调用 MyFactoryBean isSingleton
调用 MyFactoryBean getObject
bean1 bean :class com.zjq.factorybeantest.MyService
==============================
bean2 bean : class com.zjq.factorybeantest.MyFactoryBean
可以看到,bean1其实调用的是 FactoryBean中getObject()方法里面返回的实例。
bean2 因为加了 & ,所以返回的还是原来的MyFactoryBean,没有走getObject()。
为何加了个&符号,返回的还是原来的实例,下面看源码。
3. FactoryBean源码解析
老规矩,我们直接进入refresh()方法。
当容器启动的时候 ,最后会调用到doGetBean。
org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)
--->org.springframework.context.support.AbstractApplicationContext#refresh
---> org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
--->org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
--->org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
--->org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
详细看看doGetBean方法(逻辑很长)
/**
* 返回bean的实例,该实例可能是单例bean 也有可能是原型的bean
* @param name bean的名称 也有可能是bean的别名
* @param requiredType 需要获取bean的类型
* @param args 通过该参数传递进来,到调用构造方法时候发现有多个构造方法,我们就可以通过该参数来指定想要的构造方法了
* 不需要去推断构造方法(因为推断构造方法很耗时)
* @param typeCheckOnly 判断当前的bean是不是一个检查类型的bean 这类型用的很少.
* @return 返回一个bean实例
* @throws BeansException 如何bean不能被创建 那么就回抛出异常
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 在这里 传入进来的name 可能是 别名, 也有可能是工厂bean的name,所以在这里需要转换
* factoryBean的前缀在这里去除的
*/
final String beanName = transformedBeanName(name);
Object bean;
//尝试去缓存中获取对象 第一次加载时候为null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* /*
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例(比如mybatis集成spring)。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*
*
*
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
/**
* spring 只能解决单例对象的setter 注入的循环依赖,不能解决构造器注入
*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/**
* 判断AbstractBeanFacotry工厂是否有父工厂(一般情况下是没有父工厂因为abstractBeanFactory直接是抽象类,不存在父工厂)
* 一般情况下,只有Spring 和SpringMvc整合的时才会有父子容器的概念,
* 比如我们的Controller中注入Service的时候,发现我们依赖的是一个引用对象,那么他就会调用getBean去把service找出来
* 但是当前所在的容器是web子容器,那么就会在这里的 先去父容器找
*/
BeanFactory parentBeanFactory = getParentBeanFactory();
//若存在父工厂,切当前的bean工厂不存在当前的bean定义,那么bean定义是存在于父beanFacotry中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//获取bean的原始名称
String nameToLookup = originalBeanName(name);
//若为 AbstractBeanFactory 类型,委托父类处理
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// 委托给构造函数 getBean() 处理
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// 没有 args,委托给标准的 getBean() 处理
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
/**
* 方法参数 typeCheckOnly ,是用来判断调用 #getBean(...) 方法时,表示是否为仅仅进行类型检查获取 Bean 对象
* 如果不是仅仅做类型检查,而是创建 Bean 对象,则需要调用 #markBeanAsCreated(String beanName) 方法,进行记录
*/
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
/**
* 从容器中获取 beanName 相应的 GenericBeanDefinition 对象,并将其转换为 RootBeanDefinition 对象
* <bean id="tulingParentCompent" class="com.tuling.testparentsonbean.TulingParentCompent" abstract="true">
<property name="tulingCompent" ref="tulingCompent"></property>
</bean>
<bean id="tulingSonCompent" class="com.tuling.testparentsonbean.TulingSonCompent" parent="tulingParentCompent"></bean>
*/
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前创建的bean定义是不是抽象的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
/**
*
* @Bean
public DependsA dependsA() {
return new DependsA();
}
@Bean
@DependsOn(value = {"dependsA"})
public DependsB dependsB() {
return new DependsB();
}
* 处理dependsOn的依赖(这个不是我们所谓的循环依赖 而是bean创建前后的依赖)
*/
//依赖bean的名称
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// <1> 若给定的依赖 bean 已经注册为依赖给定的 bean
// 即循环依赖的情况,抛出 BeanCreationException 异常
for (String dep : dependsOn) {
//beanName是当前正在创建的bean,dep是正在创建的bean的依赖的bean的名称
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//保存的是依赖 beanName 之间的映射关系:依赖 beanName - > beanName 的集合
registerDependentBean(dep, beanName);
try {
//获取depentceOn的bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//创建单例bean
//getSingleton中的第二个参数类型是ObjectFactory<?>,是一个函数式接口,不会立刻执行,而是在
//getSingleton方法中,调用ObjectFactory的getObject,才会执行createBean
if (mbd.isSingleton()) {
//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
sharedInstance = getSingleton(beanName, () -> {
try {
//!!!!!!!!进入创建bean的逻辑!!!!!!!!!!!!
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
destroySingleton(beanName);
throw ex;
}
});
/**
* ps: 比如此时一个类 MyFactoryBean 实现了 FactoryBean 则,context.getBean("&myFactoryBean")时候:
* name 是 &MyFactoryBean ,beanName 是 MyFactoryBean(在transformedBeanName方法中判断去除了&)
* 返回的bean 就是 MyFactoryBean ioc 第一次 加载的时候 走这里
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
当 name=&myFactoryBean beanName=myFactoryBean时,
调用getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
此时返回的是 myFactoryBean。那么为何 加不加& 结果却不一样呢?我们再来看看
Object bean1 = context.getBean(“myFactoryBean”); 方法。
最后其也是调用到了doGetBean。但是这次缓存中有值,所以会走到这段逻辑
我们再来进去看看getObjectForBeanInstance(sharedInstance, name, beanName, null);方法
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 如果 name 以 & 开头,但 beanInstance 却不是 FactoryBean,则认为有问题。
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
/**
* 如果上面的判断通过了,表明 beanInstance 可能是一个普通的 bean,也可能是一个
* FactoryBean。如果是一个普通的 bean,这里直接返回 beanInstance 即可。(就是判断name 有没有带 & )
* 如果是 FactoryBean,则要调用工厂方法生成一个 bean 实例。 即 走下面 getObjectFromFactoryBean(factory, beanName, !synthetic)
*/
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
/**
* 如果 mbd 为空,则从缓存中加载 bean。FactoryBean 生成的单例 bean 会被缓存
* 在 factoryBeanObjectCache 集合中,不用每次都创建
*/
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 经过前面的判断,到这里可以保证 beanInstance 是 FactoryBean 类型的,所以可以进行类型转换
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 如果 mbd 为空,则判断是否存在名字为 beanName 的 BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
// synthetic 字面意思是"合成的"。通过全局查找,我发现在 AOP 相关的类中会将该属性设为 true。
// 所以我觉得该字段可能表示某个 bean 是不是被 AOP 增强过,也就是 AOP 基于原始类合成了一个新的代理类。
// 不过目前只是猜测,没有深究
boolean synthetic = (mbd != null && mbd.isSynthetic());
!!!!!!!调用 getObjectFromFactoryBean 方法继续获取实例 获取的就是getObject()中的方法 !!!!!!
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
/**
* FactoryBean 也有单例和非单例之分,针对不同类型的 FactoryBean,这里有两种处理方式:
* 1. 单例 FactoryBean 生成的 bean 实例也认为是单例类型。需放入缓存中,供后续重复使用
* 2. 非单例 FactoryBean 生成的 bean 实例则不会被放入缓存中,每次都会创建新的实例
**/
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 从缓存中取 bean 实例,避免多次创建 bean 实例
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 使用工厂对象中创建实例 !!!FactoryBean的getObject()!!!
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
//判断当地的bean是否正在创建
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
// 这里的 beanName 对应于 FactoryBean 的实现类, FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中
if (containsSingleton(beanName)) {
// 这里的 beanName 对应于 FactoryBean 的实现类, FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
doGetObjectFromFactoryBean(factory, beanName);
此时,调用链全部完毕。
那么,& 是在哪里判断的呢?
其实就在getObjectForBeanInstance中的这个判断
public static boolean isFactoryDereference(@Nullable String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
如果我们context.getBean("&myFactoryBean");带了& 符号
即直接返回 beanInstance 即 我们的 myFactoryBean。否则 调用 getObjectFromFactoryBean(factory, beanName, !synthetic);走到其实现类的getObject()。
大功完成
4.结语
世上无难事,只怕有心人,每天积累一点点,fighting!!!
2021,加油,fighting,希望可以少些crud啦!