zoukankan      html  css  js  c++  java
  • spring源码学习之旅(二) 结合源码聊聊FactoryBean

    一、什么是FactoryBean

              FactoryBean是由spring提供的用来让用户可以自定bean创建的接口;实现该接口可以让你的bean不用经过spring复杂的bean创建过程,但同时也能做到拿来即用,按需加载;该接口提供的方法如下:

    /**
    *  获取FactoryBean管理的对象的实例 一般由spring自动调用 无需手动调用
    */
    T getObject() throws Exception;
    
    /**
    * 获取FactoryBean管理的对象的类型
    */
    Class<?> getObjectType();
    
    /**
    * 判断FactoryBean管理的对象是否是单例  默认为单例
    * 如果返回为false,则spring不会使用factoryBeanObjectCache来缓存已加载的对象实例,
    * 每次都会创建一个全新的对象
    */
    default boolean isSingleton() {
    		return true;
    }

    二、FactoryBean在spring中的加载过程

         测试环境准备:

    1. 自定义一个FactoryBean实现类,返回对应的测试实例Person类,代码如图:
    2. 为了便于代码debug,使用xml的配置方式进行配置,如图:
    3. 启动代码如下:通过以上环境debug可以发现,当spring容器加载完后在BeanFactory的一级缓存singletonObjects中有myFactoryBean而并没有person类的实例,那ac.getBean("myFactoryBean")是怎么拿到Person的呢我们可以通过剖析getBean("myFactoryBean")这个方法来进行分析:当spring想要获取某个bean的时候,首先会从缓存中获取这个bean(参加org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)),当需要获取myFactoryBean时,由于xml中有对myFactoryBean的配置所以容器启动的时候myFactoryBean就已经被存到缓存中去了,所以从缓存中能直接获取,接下来会调用专门针对加载实现了FactoryBean接口的实现类的方法:getObjectForBeanInstance()==》getObjectFromFactoryBean()==》doGetObjectFromFactoryBean;其中会在doGetObjectFromFactoryBean中调用getObject方法返回具体的对象实例,getObjectFromFactoryBean方法中会根据isSingleton方法的具体实现判断要不要把对应实例加载到factoryBeanObjectCache缓存中;下面贴上这个三个核心方法的方法签名和源码:

              org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance:

    protected Object getObjectForBeanInstance(
    			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    		/**
    		 *  Don't let calling code try to dereference the factory if the bean isn't a factory.
    		 * 	判断是否是FactoryBean的子接口,是则设置isFactoryBean为true并返回
    		 */
    		if (BeanFactoryUtils.isFactoryDereference(name)) {
    			if (beanInstance instanceof NullBean) {
    				return beanInstance;
    			}
    			if (!(beanInstance instanceof FactoryBean)) {
    				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
    			}
    			if (mbd != null) {
    				mbd.isFactoryBean = true;
    			}
    			return beanInstance;
    		}
    
    		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
    		// If it's a FactoryBean, we use it to create a bean instance, unless the
    		// caller actually wants a reference to the factory.
    		// 判断我们拿到的bean实例是不是factoryBean,如果不是直接返回
    		if (!(beanInstance instanceof FactoryBean)) {
    			return beanInstance;
    		}
    
    		Object object = null;
    		if (mbd != null) {
    			mbd.isFactoryBean = true;
    		}
    		else {
    			// 从factoryBean的缓存factoryBeanObjectCache中尝试获取bean信息
    			object = getCachedObjectForFactoryBean(beanName);
    		}
    		if (object == null) {
    			// Return bean instance from factory.
    			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    			// Caches object obtained from FactoryBean if it is a singleton.
    			if (mbd == null && containsBeanDefinition(beanName)) {
    				mbd = getMergedLocalBeanDefinition(beanName);
    			}
    			boolean synthetic = (mbd != null && mbd.isSynthetic());
    			// 调用getObject获取factoryBean管理的bean实例
    			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    		}
    		return object;
    	}

                org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean:

    点击查看代码
    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    		if (factory.isSingleton() && containsSingleton(beanName)) {
    			synchronized (getSingletonMutex()) {
    				Object object = this.factoryBeanObjectCache.get(beanName);
    				if (object == null) {
    					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) {
    							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);
    							}
    						}
    						if (containsSingleton(beanName)) {
    							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;
    		}
    	}

              org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean:

    点击查看代码
    private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
    		Object object;
    		try {
    			if (System.getSecurityManager() != null) {
    				AccessControlContext acc = getAccessControlContext();
    				try {
    					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
    				}
    				catch (PrivilegedActionException pae) {
    					throw pae.getException();
    				}
    			}
    			else {
    				object = factory.getObject();
    			}
    		}
    		catch (FactoryBeanNotInitializedException ex) {
    			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    		}
    
    		// Do not accept a null value for a FactoryBean that's not fully
    		// initialized yet: Many FactoryBeans just return null then.
    		if (object == null) {
    			if (isSingletonCurrentlyInCreation(beanName)) {
    				throw new BeanCurrentlyInCreationException(
    						beanName, "FactoryBean which is currently in creation returned null from getObject");
    			}
    			object = new NullBean();
    		}
    		return object;
    	}

    三、FactoryBean和BeanFactory的区别

    1.  BeanFactoryBeanFactory是spring定义的创建bean的一个顶层父接口,其定义了获取bean的方法,咱们常见的ApplicationContext和DefaultListableBeanFactory都间接实现了它;实现了BeanFactory意味着创建的bean必须要经过spring定义的复杂的各种生命周期方法;
    2. FactoryBeanFactoryBean同样可以创建bean,但是其管理的bean可以不经过spring定义的创建的bean的生命周期,也可以不通过反射直接获取;可以针对不同的需求定制化FactoryBean,相当于一个创建工厂的bean,而这个工厂bean又可以创建不同的对象实例

    四、FactoryBean的实际运用场景

           据我所知像Mybatis,dubbo以及springcloud这些开源框架中都有使用factoryBean来创建对象,但是由于本人并没有去看这些框架的源码也没有过多的了解所以这里暂且不表,所以在这里贴一个通过FactoryBean创建定时任务的例子;

           项目中定时任务的使用还是比较频繁的,设置有时候会多到专门开一个服务器去跑这些定时任务,而定时任务无非关注几点,一是任务的间隔时间,二是任务的执行逻辑;

    1. 定义一个CommonTask来统一管理任务的间隔时间以及具体执行的service;
    2. 定义TaskFactoryBean实现FactoryBean接口,用来生成CommonTask的实例
    3. 定义一个TaskConfig类用来按需生成不同的CommonTask以上只是提供了粗略的实现思路,具体的等抽空补代码。。。

            

    希望每get一个知识点都能坚持用博客记录下来,加油!
  • 相关阅读:
    k8s管理pod资源对象(上)
    k8spod资源的基础管理操作
    k8s名称空间资源
    bootstrap表格 之多选数据的获取
    sql server 查询表的创建时间
    C# Bootstrap table之 分页
    C# 基于Bootstrap的三级联动
    C# 后台构造json数据
    C# bootstrap之表格动态绑定值
    C# 文件的一些基本操作
  • 原文地址:https://www.cnblogs.com/darling2047/p/15020071.html
Copyright © 2011-2022 走看看