zoukankan      html  css  js  c++  java
  • Spring FactoryBean 源码分析

    一、FactoryBean的作用

    Spring 中有两种 bean ,一种是普通 bean ,另外一种则是 FactoryBean. 普通 bean 返回的是指定类的一个实例对象,而 FactoryBean 则不同,它返回的对象不是某一个指定类的实例对象,而是该 FactoryBean 的 getObject() 方法所返回的对象,创建出来的对象是单例还是多例,由 FactoryBean 的 isSingleton() 方法来控制.

    一般情况下, Spring 通过获取 bean 标签中配置的 class 属性的全类名,通过反射(Class.forName(String className)来创建 bean 对象,但是在某些情况下,有一些 bean 的实例化过程比较复杂,如果按照传统的方式,则需要在 <bean...> 标签中配置大量的信息,配置方式的灵活性是受限制的,这个时候通过获取配置然后编码的方式来实例化 bean,可能只会得到一个简单的方案,不能满足我们实际的需求,为了解决这个问题, Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口,通过该接口实现类中的 getObject() 方法私人订制 bean 的实现逻辑,这样就大大的增加了灵活性.同时这样也可以隐藏实例化 bean 的一些复杂的细节,给上层的调用带来了便利.

    二、FactoryBean的使用特点

    实现了 FactoryBean 接口的 bean 如果通过配置的 id 去获取,获取到的是 FactoryBean 调用 getObject()方法返回的对象,而不是FactoryBean 本身,如果想要获取到 FactoryBean 本身,需要在 id前面加上一个 & 符号,例如:

    applicationContext.getBean("&id")
    

    三、FactoryBean 案例演示  

    1、FactoryBean 接口的实现类

    // 自定义类 Person 实现 FactoryBean 接口
    public class Person implements FactoryBean<Mango> {
        @Override
        public Mango getObject() throws Exception {
            Mango mango = new Mango();
            mango.setName("mango");
            mango.setColor("yellow");
            mango.setColor("10.0");
            return mango;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
    		// 返回值是 true,代表创建的 Mango 对象是单例的,反之为多例
            return true;
        }
    }
    

    2、spring 配置文件(classpath:spring-config/spring-ioc.xml 配置文件)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="person" class="com.xiaomaomao.entity.Person"></bean>
    </beans>
    

    3、测试类

    public class SpringTest {
        public static void main(String[] args) {
            ApplicationContext ioc = new ClassPathXmlApplicationContext("classpath:spring-config/spring-ioc.xml");
            // 获取到的是 FactoryBean 本身实例对象
            Object person01 =ioc.getBean("&person");
            // 获取到的是 FactoryBean 调用 getObject() 方法返回的对象
            Object person02 = ioc.getBean("person");
            Object person03 = ioc.getBean("person");
    
            // 输出 FactoryBean 本身实例对象
            System.out.println(person01);
            // 输出 FactoryBean 调用 getObject() 方法返回的对象
            System.out.println(person02);
            // 判断 FactoryBean 调用 getObject() 方法返回的对象是不是单例
            System.out.println(person02 == person03);
        }
    }
    

    4、测试结果

    通过测试结果,我们可以得出以下结论:

    (1)、getBean("&id") 获取到的是 FactoryBean 本身对象

    (2)、getBean("id") 获取到的是 FactoryBean 调用 getObject() 方法返回的对象

    (3)、isSingleton() 方法可以控制 FactoryBean 调用 getObject() 方法返回的对象是单例还是多例

    四、FactoryBean 的实际应用

    就拿 Mybatis 来说吧,我们也是通过注入一个 SqlSessionFactoryBean ,实际上使用的却是 SqlSessionFactoryBean 对象通过调用 getObject() 方法返回的 SqlSessionFactory 对象.

    <!-- spring 和 MyBatis 整合,不需要 mybatis 的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource"/>
    	<!-- 自动扫描 mapping.xml 文件 -->
    	<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>

    五、FactoryBean 源码解析

    说到这里就简单说一下 FactoryBean 的初始化和获取 IOC 中的 bean 的过程吧

    // DefaultListableBeanFactory 类中的方法,代码行号: 728
    public void preInstantiateSingletons() throws BeansException {
    	if (this.logger.isDebugEnabled()) {
    		this.logger.debug("Pre-instantiating singletons in " + this);
    	}
    
    	// 这里的 this 代表的是 DefaultListableBeanFactory 
    	// 这个类里面封装了 spring 配置文件中所有,bean 标签的配置信息
    	List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
    
    	// 触发所有非懒加载的单例 bean 的初始化动作
    	for (String beanName : beanNames) {
    		// 合并父 bean 的配置
    		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    		// 非懒加载、非抽象的单例 bean
    		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    			// 判断当前 bean 是否是 FactoryBean (我们配置的 person 这个 bean 由于实现了 FactoryBean 这个接口
    			// 所以它属于 FactoryBean
    			if (isFactoryBean(beanName)) {
    				// FactoryBean 的初始化动作,这里的 FACTORY_BEAN_PREFIX 是一个前缀 & 
    				final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
    				boolean isEagerInit;
    				if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    					isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
    						@Override
    						public Boolean run() {
    							return ((SmartFactoryBean<?>) factory).isEagerInit();
    						}
    					}, getAccessControlContext());
    				}
    				else {
    					isEagerInit = (factory instanceof SmartFactoryBean &&
    							((SmartFactoryBean<?>) factory).isEagerInit());
    				}
    				if (isEagerInit) {
    					getBean(beanName);
    				}
    			}
    			else {
    				// 普通 bean 的初始化
    				getBean(beanName);
    			}
    		}
    	}
    
        // 到这里为止,我们所说的非懒加载非抽象的所有 singleton bean 已经初始化完毕
    	// 如果我们定义的 bean 实现了 SmartInitializingSingleton 这个接口,那么会在这里回调
    	for (String beanName : beanNames) {
    		Object singletonInstance = getSingleton(beanName);
    		if (singletonInstance instanceof SmartInitializingSingleton) {
    			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    			if (System.getSecurityManager() != null) {
    				AccessController.doPrivileged(new PrivilegedAction<Object>() {
    					@Override
    					public Object run() {
    						smartSingleton.afterSingletonsInstantiated();
    						return null;
    					}
    				}, getAccessControlContext());
    			}
    			else {
    				smartSingleton.afterSingletonsInstantiated();
    			}
    		}
    	}
    }

    由于我们在 Spring 的配置文件中配置的 bean 是一个 FactoryBean ,所以我们点进去 (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName) 这个方法看一下,这个方法的参数是 &person (person 这个是 id ,我们在配置文件中配置的,解析 XML 的时候,这个 id 就赋值给了我们这里的 beanName)

    // AbstractBeanFactory 类中的方法,代码行号: 196
    public Object getBean(String name) throws BeansException {
    	return doGetBean(name, null, null, false);
    }
    

     同时可以看一下下面几个重载的方法,这个几个方法是我们获取 IOC 容器中 bean 的一些方法,当然上面那个方法既可以初始化 bean,也可以获取 IOC 容器中的 bean 对象

    // 获取 bean 的时候   ioc.getBean("person",Person.class)
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    	return doGetBean(name, requiredType, null, false);
    }
    // 获取 bean 的时候   ioc.getBean("person","xiaomao")
    public Object getBean(String name, Object... args) throws BeansException {
    	return doGetBean(name, null, args, false);
    }
    // 获取 bean 的时候   ioc.getBean("person", Person.class,"xiaomao","xiaomaomao")
    public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
    	return doGetBean(name, requiredType, args, false);
    }
    

    不管是初始化 bean 还是获取 IOC 容器中的 bean ,我们都最终会调用 doGetBean(....) 这个方法,只是不同的需求下传入的参数值不同而已.点进去这个方法,看看里面到底有什么

    // AbstractBeanFactory 类中的方法,代码行号: 235
    protected <T> T doGetBean(
    			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
    			throws BeansException {
    
    	// 对于普通的 bean,不管是初始化 bean 还是获取 bean, beanName 的值是不会有变化的,自始至终都是一样
    	// 而对于 FactoryBean 来说,初始化 bean 的时候,由于传进来的参数 name 是带有 & 符号的,例如 &person
    	// 这里是想真正的获取到 FactoryBean 的 beanName ,所以会去掉 & 符号
    	final String beanName = transformedBeanName(name);
    	
    	// 这个要关注一下,创建 bean 、获取 bean 的返回值
    	Object bean;
    
    	// 判断父容器中是否已经创建过了该单例 bean
    	// 第一次初始化的时候,这里是没有创建过该单例 bean 的,所以值为 null
    	// 如果是后面通过 getBean(...) 来获取的 bean 实例的时候,因为初始化已经创建了 bean ,所以这里就不会为 null
    	Object sharedInstance = getSingleton(beanName);
    	// 如果没有创建该 singleton bean ,并且传入的参数为 null ,那么执行获取 bean 的操作
    	// 如果获取 bean 实例的时候,传入了 args 参数,因为已经创建过了该 bean 实例,所以 sharedInstance 不为 null 
    	// 这个时候如果传入的 args 参数不为 null ,那么就不满足该条件,这里就不是 获取 bean 了,而是需要创建 bean
    	// 例如: ioc.getBean("person","xiaomao") ,这种情况会跳到下面的 else 分支中,就不是获取 bean,而是创建 bean
    	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 + "'");
    			}
    		}
    		
    		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    	}
    	
    	// 执行创建 bean 的操作
    	// 如果我们通过 getBean(beanName,args) 传入了 args 参数,那么我们就不是获取 bean 了,而是要创建 bean 
    	else {
    		// 如果已经创建了该 beanName 的 prototype ,那么抛出异常
    		if (isPrototypeCurrentlyInCreation(beanName)) {
    			throw new BeanCurrentlyInCreationException(beanName);
    		}
    
    		// 检查是否这个 BeanDefinition 对象已经存在父容器中了
    		BeanFactory parentBeanFactory = getParentBeanFactory();
    		// 如果自身容器中不存在,父容器中存在该 BeanDefiniton
    		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    			// Not found -> check parent.
    			String nameToLookup = originalBeanName(name);
    			if (args != null) {
    				// Delegation to parent with explicit args.
    				return (T) parentBeanFactory.getBean(nameToLookup, args);
    			}
    			else {
    				// No args -> delegate to standard getBean method.
    				return parentBeanFactory.getBean(nameToLookup, requiredType);
    			}
    		}
    		// 标记已经创建了这个 bean
    		if (!typeCheckOnly) {
    			markBeanAsCreated(beanName);
    		}
    
    		try {
    			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    			checkMergedBeanDefinition(mbd, beanName, args);
    
    			// Guarantee initialization of beans that the current bean depends on.
    			String[] dependsOn = mbd.getDependsOn();
    			if (dependsOn != null) {
    				for (String dep : dependsOn) {
    					if (isDependent(beanName, dep)) {
    						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    					}
    					registerDependentBean(dep, beanName);
    					getBean(dep);
    				}
    			}
    
    			// 创建 bean 实例对象
    			if (mbd.isSingleton()) {
    				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
    					@Override
    					public Object getObject() throws BeansException {
    						try {
    							// 创建 bean 对象,核心方法...(我们这里就不看了,还是蛮多的)
    							return createBean(beanName, mbd, args);
    						}
    						catch (BeansException ex) {
    							// Explicitly remove instance from singleton cache: It might have been put there
    							// eagerly by the creation process, to allow for circular reference resolution.
    							// Also remove any beans that received a temporary reference to the bean.
    							destroySingleton(beanName);
    							throw ex;
    						}
    					}
    				});
    				// 如果是普通 bean ,返回自身对象
    				// 如果是 FactoryBean 返回自身对象,而不是调用 getObject() 方法返回的对象
    				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, new ObjectFactory<Object>() {
    						@Override
    						public Object getObject() throws BeansException {
    							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 && bean != null && !requiredType.isInstance(bean)) {
    		try {
    			return getTypeConverter().convertIfNecessary(bean, requiredType);
    		}
    		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;
    }
    

    看一下这个方法,虽然比较长,我们只关心我们需要的部分,上面这个方法不管最后执行哪一个分支,最终都会调用 bean = getObjectForBeanInstance(...) 这个方法,点进去看吧.

    // AbstractBeanFactory 类中的方法,代码行号: 1607
    protected Object getObjectForBeanInstance(
    			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
    	// 两个判断条件
    	// BeanFactoryUtils.isFactoryDereference(name):判断 name 是否不为空,并且以 & 开头
    	// beanInstance instanceof FactoryBean:当前 bean 是否是 FactoryBean 的实现类
    	
    	
    	if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
    		throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    	}
    
    	// 初始化的时候,如果是 FactoryBean ,那么上述两个判断条件都是成立的,直接返回一个 beanInstance 对象
    	// 获取对象的时候,如果通过 ioc.getBean("&person") 这种方式,那么也是直接返回一个 beanInstance 对象
    	// 这里的 beanInstance 是我们在 AbstractBeanFactory 类中通过调用 createBean(beanName, mbd, args)
    	// 方法创建的,它是一个 Person 类的对象,不是 FactoryBean 实现类调用 getObject() 方法生产的对象
    	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    		return beanInstance;
    	}
    	
    	// 如果是已经初始化完毕了,去 IOC 容器中获取 bean 实例对象的时候
    	// 如果通过 ioc.getBean("person") 获取 bean 实例对象,会执行如下代码
    	Object object = null;
    	if (mbd == null) {
    		object = getCachedObjectForFactoryBean(beanName);
    	}
    	if (object == null) {
    		// beanInstance 是 Person 对象,而 Person 又是实现了 FactoryBean 接口的
    		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    	
    		if (mbd == null && containsBeanDefinition(beanName)) {
    			mbd = getMergedLocalBeanDefinition(beanName);
    		}
    		boolean synthetic = (mbd != null && mbd.isSynthetic());
    		// 获取 FactoryBean 的核心方法....
    		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    	}
    	return object;
    }
    

    从上面代码我们知道, ioc.get("&person") 获取到的是 Person 类对象,如果我们要获取 Person 对象调用 getObject() 方法生产的 Mango 对象,该如何获取呢?

    找到 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) {
    				// FactoryBean 调用 getObject() 方法生产的对象
    				object = doGetObjectFromFactoryBean(factory, beanName);
    				Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
    				if (alreadyThere != null) {
    					object = alreadyThere;
    				}
    				else {
    					if (object != null && shouldPostProcess) {
    						try {
    							object = postProcessObjectFromFactoryBean(object, beanName);
    						}
    						catch (Throwable ex) {
    							throw new BeanCreationException(beanName,
    									"Post-processing of FactoryBean's singleton object failed", ex);
    						}
    					}
    					this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
    				}
    			}
    			return (object != NULL_OBJECT ? object : null);
    		}
    	}
    	else {
    		// FactoryBean 调用 getObject() 方法生产的对象
    		Object object = doGetObjectFromFactoryBean(factory, beanName);
    		if (object != null && 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) 这个方法里面,继续点进去看

    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
    			throws BeanCreationException {
    
    	Object object;
    	try {
    		if (System.getSecurityManager() != null) {
    			AccessControlContext acc = getAccessControlContext();
    			try {
    				object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
    					@Override
    					public Object run() throws Exception {
    							return factory.getObject();
    						}
    					}, acc);
    			}
    			catch (PrivilegedActionException pae) {
    				throw pae.getException();
    			}
    		}
    		else {
    			// 这里的 factory 就是 FactoryBean 实现类对象,我们这里就是 Person 类对象
    			// 根据继承的关系,子类中实现了 getObject() 方法,那么实际调用的就是子类里的 getObject()方法
    			// 也就是我们 Person 对象中的 getObject() 方法
    			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 && isSingletonCurrentlyInCreation(beanName)) {
    		throw new BeanCurrentlyInCreationException(
    				beanName, "FactoryBean which is currently in creation returned null from getObject");
    	}
    	// 将BeanFactory 实现类对象通过调用 getObject() 方法生产的对象返回出去.
    	return object;
    }
    

      

     

  • 相关阅读:
    CentOS安装配置ganglia
    k-means聚类算法
    SharePoint solution and feature management with PowerShell
    EM算法
    极客”一词,来自于美国俚语“geek”的音译,一般理解为性格古怪的人
    学习游戏要学习编程语言吗?十大主流编程语言解析
    platform_device与platform_driver
    《用户体验要素》澄清了 UI 原型设计中看不见确感受得到的那一层
    ipconfig /flushdns 清除系统DNS缓存
    typedef和define具体的具体差别
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/13991529.html
Copyright © 2011-2022 走看看