spring源码学习笔记(二)FactoryBean的使用和源码解析

spring源码学习笔记(二)FactoryBean的使用和源码解析

每天多学一点点~
话不多说,这就开始吧…

1.前言

BeanFactory和FactoryBean的区别?之前一直有点迷迷糊糊,最近重看spring源码,遂研究记录一下。
先说结论:

  1. BeanFactory是Bean的工厂,Spring的顶层核心接口。没有BeanFactory就没有Bean的存在,工厂只负责按照要求生产Bean。Bean的定义信息,要生产成什么样由ApplicationContext说了算。ApplicationContext面向的是用户,所以需要更好地服务用户,不仅要提供Bean和调用工厂去生产Bean,还要提供一系列人性化的服务(如国际化,加载Bean定义、监听等),怎么生成Bean的事交给工厂去做。
  2. 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。比如下面这个示例:

  1. Config 类
@Configuration
@ComponentScan("com.zjq.factorybeantest")
public class Config {
}
  1. MyService类
@Service("myService")
public class MyService {
	public void getUser() {
		System.out.println(" 调用  MyService   getUser 方法");
	}
}
  1. 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;
	}
}
  1. 调用类
	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啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值