Spring源码深度解析(郝佳)-学习-FactoryBean 使用及源码解析

20 篇文章 1 订阅
18 篇文章 0 订阅

FactoryBean 使用
一般情况下,Spring 通过反射机制利用 Bean 的 class 属性指定实现类实例化 bean,在某些情况下,实例化 bean 过程比较复杂,如果按照传统方式,则需要在中提供大量的配置信息,配置方式的灵活是受限制的,这里采用编码方式可能会得到一个简单的方案,在 Spring 为此提供了一个 org.Springframework.bean.factory.FactoryBean 工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。
FactoryBean 接口对于 Spring 框架来说占有重要的地位,Spring 自身就提供了70多个 FactoryBean 实现,它们隐藏了实例化一些得要 bean 的细节,给上层应用带来了便利,从 Spring3.0开始,FactoryBean 开始支持泛型,即使接口声明改为 FactoryBean<T>的形式。

public interface FactoryBean<T>{
	T getObject() throws Exception;
	Class <?> getObjectType();
	bean isSingleton();
}

在该接口中还定义了以下3个方法:

  • T getObject(): 返回由 FactoryBean 创建的 bean 实例,如果 isSingleton() 返回 true
    ,则该实例会放到 Spring 容器中单例实例缓存池中。
  • boolean isSingleton(): 返回由 FactoryBean创建的 bean实例的作用域 singleton 还是 prototype。
  • Class<T> getObjectType() :返回 FactoryBean 创建的 bean 类型。

当配置文件中的 <bean>的 class 属性配置的实例类是 FactoryBean 时,通过 getBean()方法所返回的对象,相当于 FactoryBean#getObject()代理了 getBean()方法,例如:如果使用传统方式配置下面 Car 的<bean>时,Car 的每个属性分别对应一个<property>元素标签。

@Data
public class Car {
    private String brand;
    private int maxSpeed;
    private double price ;
}

如果用 FactoryBean 的方式实现就会灵活一些,下例通过逗号分割符的方式一次性地为 Car 所有属性指定配置值:

import org.springframework.beans.factory.FactoryBean;

public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.parseInt(infos[1]));
        car.setPrice(Double.parseDouble(infos[2]));
        return car;
    }
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }
    @Override
    public boolean isSingleton() {
        return false;
    }
    public String getCarInfo() {
        return carInfo;
    }
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

有了这个 CarFactoryBean 后,就可以配置文件中使用下面的这种自定义的配置方式配置 CarBean 了:
<bean id=“car” class=“com.test.factoryBean.CarFactoryBean” carInfo=“超级跑车,400,2000000” >
当调用 getBean(“car”)时,Spring通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject()方法返回,如果希望获取 CarFactoryBean 的实例,则需要在使用 getBean(beanName) 方法时在 beanName 前显示的加上"&“前缀,例如 getBean(”&car")
到这里我们测试一下:

public class Test32 {

   /**
     * Bean 的定义信息
     * Bean 实现类
     * Spring  本身
     *  如果采用基于 XML 的配置,Bean 的定义信息和 Bean 的实现类本身是分离的,而采用基于注解的配置文件时。
     *  Bean 的定义信息即通过 Bean 实现类上的标注注解实现。
     *
     */
    public static void main(String[] args) throws Exception {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_31_40/spring32_factory_bean.xml");
        Car car = (Car) ac.getBean("car");
        System.out.println(JSON.toJSONString(car));
        CarFactoryBean carFactoryBean = (CarFactoryBean) ac.getBean("&car");
        Car car1 = carFactoryBean.getObject();
        System.out.println(car == car1);
    }
}

首先我们来看 bean 的解析。

DefaultBeanDefinitionDocumentReader.java

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	// BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义封装类
	// 对文档中的<Bean>元素解析由BeanDefinitionParserDelegate实现
	
	if (bdHolder != null) {
		/***
		 * 如果需要的话就对 beanDefinition 进行装饰,那么这句代码的作用就是什么功能呢?
		 * 这句代码的使用场景如下:
		 * <bean id="test" class="test.MyClass">
		 *     <mybean:user username="aaaa"/>
		 * </bean>
		 * 当 Spring 中的 bean 使用了默认的标签配置,但是其中的子元素却使用了自定义的配置,这句代码就起作用了,可能会有人会疑问,
		 * 之前讲过,对 bean 的解析分成两种类型,一种是默认的类型解析,另一种是自定义类型解析,这不正是自定义类型解析吗?为什么会在
		 * 默认的类型解析中单独的添加一个方法的处理呢,确实,这个问题很让人迷惑,但是,不知道聪明的读者有没有发现,这个自定义类型并不是
		 * 以 Bean 的形式出现的呢?我们之前讲过两种类型的不同处理只是针对 bean 的,这里我们看到,这个自定义类型其实是属性,好了,我们
		 * 我们继续分析这个代码
		 */
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// Register the final decorated instance.
			// 向Spring Ioc容器注册解析得到的bean定义,这是Bean定义向Ioc容器注册的入口
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// Send registration event.
		// 在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件
	
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

DefaultBeanDefinitionDocumentReader.java

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
    // 这里将函数中的第三个设置为空,那么第三个参数是做什么用的呢?什么情况下不为空呢?其实这第三个参数是父类的bean,当对某个嵌套
    // 配置进行分析时,这里需要传递父类beanDefinition,分析源码得知这里传递的参数其实是为了使用父类的scope属性,以备子类若没有设置
    // scope时默认使用父类的属性,这里分析的是顶层配置,所以传递null,将第三个参数设置为空后进一步跟踪函数:
    return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
// 我们总结一下 decorateBeanDefinitionIfRequired 方法的作用,在 decorateBeanDefinitionIfRequired 中,我们可以看到程序的
// 默认的标签的处理其实是直接略过的,因此,默认的标签到这里已经被处理完成,这里对自定义的标签或者说对 bean 的我自定义属性感兴趣
// 在方法中实现了寻找自定义标签并根据自定义标签寻找命名空间处理器,并进行进一步的解析
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
        Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
    BeanDefinitionHolder finalDefinition = definitionHolder;
    
    NamedNodeMap attributes = ele.getAttributes();
    //遍历所有的属性,看看是否有适用于修饰的属性
    for (int i = 0; i < attributes.getLength(); i++) {
        Node node = attributes.item(i);

        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    }

    // 遍历所有的子节点,看看是否有适用于修饰的子元素
    NodeList children = ele.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);

        if (node.getNodeType() == Node.ELEMENT_NODE) {
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
    }
    return finalDefinition;
}

BeanDefinitionParserDelegate.java

/***
 * 程序直到这里,条理其实己经非常的清楚了,首先获取属性或者元素的命名空间,以此来判断该元素或者属性是否适用于自定义标签的解析条件,
 * 找出自定义类型所对应的NamespaceHandler并进行进一步的解析,在自定义标签解析的章节我们会重点讲解,这里暂先略过
 *
 */
public BeanDefinitionHolder decorateIfRequired(
        Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
    // 获取自己定义标签的命名空间
    String namespaceUri = getNamespaceURI(node);
    // 对于非默认标签进行修饰
    if (!isDefaultNamespace(namespaceUri)) {
        // 根据命名空间找到对应的处理器
        // 程序走到这里,条理其实已经非常的清楚了,首先获取属性或者元素的命名空间,以此来判断该元素或者属性是否适用于自定义标签的解析条件
        // 找出自定义类型所对应的NamespaceHandler并进行进一步的解析
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler != null) {
            // 进行修饰
            return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
        } else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
        } else {
            // A custom namespace, not to be handled by Spring - maybe "xml:...".
            if (logger.isDebugEnabled()) {
                logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
            }
        }
    }
    return originalDef;
}

在这里插入图片描述

DefaultNamespaceHandlerResolver.java

@Override
public NamespaceHandler resolve(String namespaceUri) {
	// 获取所有已经配置的 handler 映射
	Map<String, Object> handlerMappings = getHandlerMappings();
	// 根据命名空间找到对应的信息
	Object handlerOrClassName = handlerMappings.get(namespaceUri);
	if (handlerOrClassName == null) {
		return null;
	}
	else if (handlerOrClassName instanceof NamespaceHandler) {
		//  已经做过解析的情况,直接从缓存中读取
		return (NamespaceHandler) handlerOrClassName;
	}
	else {
		// 没有做过解析,则返回的是类路径
		String className = (String) handlerOrClassName;
		try {
			// 使用反射将类路径转化成类
			Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
			if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
				throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
						"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
			}
			// 初始化类
			NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
			// 调用自定义的 NamespaceHandler 的初始化方法
			namespaceHandler.init();
			// 记录到缓存中
			handlerMappings.put(namespaceUri, namespaceHandler);
			return namespaceHandler;
		}
		catch (ClassNotFoundException ex) {
			throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
					namespaceUri + "] not found", ex);
		}
		catch (LinkageError err) {
			throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
					namespaceUri + "]: problem with handler class file or dependent class", err);
		}
	}
}

我们知道getHandlerMappings()这个方法是从项目的Spring.handlers 中获取命名的空间和 Handler 的对应关系,刚好。我们在 Spring beans包的目标下找到了 Spring.handlers
在这里插入图片描述
因此,我们得到了SimplePropertyNamespaceHandler处理器来处理 p:carInfo 标签。
再调用SimplePropertyNamespaceHandler的decorate方法。

SimplePropertyNamespaceHandler.java

@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
	if (node instanceof Attr) {
		Attr attr = (Attr) node;
		String propertyName = parserContext.getDelegate().getLocalName(attr);
		String propertyValue = attr.getValue();
		MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
		if (pvs.contains(propertyName)) {
			parserContext.getReaderContext().error("Property '" + propertyName + "' is already defined using " +
					"both  and inline syntax. Only one approach may be used per property.", attr);
		}
		if (propertyName.endsWith("-ref")) {
			propertyName = propertyName.substring(0, propertyName.length() - "-ref".length());
			pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
		}
		else {
			pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
		}
	}
	return definition;
}

得到属性名 carInfo 和属性值 “红旗 CA72,200,2000.00” 保存到 beanDefinition 的MutablePropertyValues属性中。
Bean的创建和属性的封装,这里不做过程的缀述了,因为在之前的博客中有很多己经详细的说明了 Bean 的创建,属性的封装,属性类型的转换等。
我们知道,bean 对象最终放到了容器内部 singletonObjects 集合中 。
在这里插入图片描述

AbstractBeanFactory.java


/**
 * 真正的实现向Ioc容器获取Bean的功能,也是就触发依赖注入的地方
 * 通过对IOC容器的获取Bean的的分析,我们可以看到,在Spring中,如果Bean定义为单例模式(Singleton)的,容器在创建之前先从缓存中查找
 * 以确保整个容器中只存在一个实例对象时,如果Bean定义为原型模式,则容器每次都会创建一个新的的实例对象,除此之外,Bean定义还可以指定其生命
 * 周期范围
 * 上面的源码只定义了根据Bean定义的不同模式采取的创建Bean实例对象的不同策略,具体的Bean实例对象创建过程由实现了ObjectFactory接口匿名
 * 内部类createBean()方法完成,ObjectFactory接口使用了委派模式,具体的Bean实例创建过程交由其实现类AbstractAutowireCapableBeanFactory
 * 完成,下面我们继续分析AbstractAutowireCapableBeanFactory的createBean()方法的源码,理解 创建Bean实例 具体的过程
 *
 *
 * Spring 加载 bean 的过程
 * 1.转换对应的 beanName
 * 2.或许很多的人不理解转换对应的 beanName 是什么意思,传入的参数 name 就是 beanName 吗?其实不是,这个传入的参数可能是别名,也可能是
 *   其实不是,这里传入的参数可能是别名,也可能是 FactoryBean,所以需要进行一系列的解析,这些解析的内容包括如下内容
 *   去除 FactoryBean 的修饰符,也就是如果 name="&aa" ,那么会首先去除&而使得 name = "aa" ,
 *   取指定的 alias 所表示的最终的 beanName ,例如别名 A 指向别名 B的 bean 则返回 B ;若别名 A 指向别名 B,别名 B 又指向别名 C的Bean
 *   则直接返回 C
 *   单例的在 Spring 的同一个容器内只会被创建一次,后续再获取 Bean ,就直接从单例缓存中获取了,当然,这里也只是尝试加载,首先会尝试
 *   从缓存中加载,如果加载不成功,则尝试从 singletonFactroy 中加载,因为为创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候
 *   为了避免循环依赖,在 Spring 中创建 Bean 的原则是不等 bean 创建完成就会将创建的 bean 的 ObjectBeanFactory 提前曝光加入到缓存中的
 *   一旦下一个 bean 创建的时候需要依赖上一个 bean 则直接使用BeanFactory
 * 3. bean 的实例化
 *   如果从缓存中得到 bean 的原始状态,则需要对 bean 进行实例化,这里有必要强调一下, 缓存中的记录只是原始的 bean 的状态,并不一定是我们
 *    最终想要的 bean ,举个例子,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 就完成
 *    了这个工作,后续会详细的讲解
 *  4.原型模式的依赖检查
*  只有在单例的情况下,才会尝试解决的循环依赖,如果存在 A中有 B 的属性,B 中有 A 的属性,那么当依赖注入的时候,就会产生 A 还未创建
 *   完成的时候,因为对于 B 的创建再次返回创建 A ,造成循环依赖,也就是情况,isPrototypeCurrentlyInCreation(beanName) 判断 true
 *   检测 parentBeanFactory
 *   从代码的上来看,如果缓存 没有数据的话,直接转到父类的工厂上去加载了,这是为什么呢?
 *   可能读者会忽略一个很重要的判断条件,parentBeanFactory !=null && !containsBeanDefinition(beanName)
 *   ,parentBeanFactory !=null ,parentBeanFactory  如果为空,则其他的一切都是浮云,但是!containsBeanDefinition(beanName) 就比较
 *   重要了,它是在检测如果当前加载的 xml 配置文件中不包含 beanName 所对应的配置,就只能到 parentBeanFactory 去尝试一下,然后再去
 *   递归的调用 getBean 方法
 *  6.将存储的 xml 配置文件中的 GenericBeanDefinition 转换成 RootBeanDefinition 中的,但是所有的 Bean后续处理都是针对
 *  RootBeanDefinition的,所以这里需要转换,转换的同时如果父类 bean 不为空的话,则会一并合并父类的属性
 *
 *  7.寻找依赖,因为 bean 初始化的过程很可能是会用到某些属性的,而某些属性很可能是动态配置的,并且配置成依赖于其他的 bean , 那么
 *  这个时候就有必要加载依赖的bean ,所以,在 Spring 的加载顺序中,在初始化某一个 bean 的时候,首先会初始化这个 bean 所对应的依赖
 *  8.针对不同的 scope 进行 bean 的创建
 *  我们都知道,在 Spring 中存在着不同的 scope ,其中默认的是 singleton ,但是还有一些其他的配置,诸如 prototype ,request 之类的
 *  在这个步骤中,Spring会根据不同的配置进行不同的初始化策略
 *
 *  9. 程序到这里返回 bean后已经基本的结果了,通常对该方法的调用参数 requiredType 是为空的,但是可能会存在这样的一种情况,返回的 bean
 *  其实是 String 类型的,但是 requiredType 传入的是 Integer类型,那么这个时候本步骤会直到了作用,它的功能是将返回bean 转换成
 *  requiredType 所指定的类型,当然,String  转换为 Integer 是最简单的一种转换,在 Spring 提供了各种各样的转换器,用户也可以自己定义
 *  自己的转换器来满足需求
 *  经过上面的步骤后bean 的加载已经结束了,这个时候就可以返回我们需要的 bean 了,直观的反映整个过程,其中最重要的步骤就是8,针对不同的
 *  scope 进行 bean 的创建,你会看到各种常用的 Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求
 *
 *  经过上面的步骤后,bean 的加载已经结束,这个时候就可以返回我们所需要的 bean 了,
 *
 *
 */
@SuppressWarnings("unchecked")
protected  T doGetBean(
		final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
		throws BeansException {
	//根据指定的名称获取被管理的Bean的名称,剥离指定的名称中对容器的相关依赖
	// 如果指定的是别名,将别名转换成规范的Bean的名称
	final String beanName = transformedBeanName(name);
	Object bean;
	//Eagerly check singleton cache for manually registered singletons.
	// 检查缓存中或者实例工厂中是否有对应的实例
	// 为什么首先会使用这段代码呢?
	// 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候,为了避免循环依赖
	// Spring 创建 bean 的原则是不等 bean 的创建完成就会将创建的 bean  的 ObjectFactory 提早曝光
	// 也就是将 ObjectBeanFactory  加入到缓存中,一旦下个 bean 创建的时候需要依赖上个 bean 则直接使用 ObjectFactory
	// 直接尝试从缓存中获取或者 singletonFactories 中的 ObjectFactory 中获取

	Object sharedInstance = getSingleton(beanName);
	// 先从缓存 中读取是否已经有被创建过的单例模式的bean
	// 对于单例模式的Bean,整个Ioc容器只创建一次,不需要重复的创建
	if (sharedInstance != null && args == null) {
			//如果在容器中已经有指定名称的单例模式的Bean,被创建,直接返回已经创建好的Bean
		// 获取给定的Bean的实例对象,主要完成FactoryBean相关处理
		// 注意:BeanFactory是管理Bean的工厂,FactoryBean是创建对象的工厂Bean,两者之间是有很多的区别的 | 返回对应的实例
		// 有个时候存在诸如 BeanFactory 的情况并不是直接返回实例本身而是返回指定方法返回的实例
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {
		//缓存中已经在有原型模式的Bean
		// 但是由于循环引用导致实例化对象失败
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		// 只有在单例的情况下都会以尝试解析循环依赖,原型模式情况下,如果存在 A 中有 B 的属性,B中有 A的属性,那么当依赖
		//  注入的时候,就会产生当 A 还示创建完成的时候因为
		// 对 B 的创建再次返回创建 A ,造成我一依赖,也就是下面的情况
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		// 对于Ioc容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否
		// 能在当前的BeanFactory中获取所需要的Bean,如果不能则委托当前的容器
		// 的父容器去查找 ,如果还是找不到,则沿着容器的继承体系向父容器中查找
		BeanFactory parentBeanFactory = getParentBeanFactory();
		//如果 beanDefinitionMap 中也就是在所有的已经加载的类中不包括
		// beanName,则尝试从 parentBeanFactory 中检测
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			// 解析指定的Bean名称的原始名称
			String nameToLookup = originalBeanName(name);
			// 递归到 BeanFactory 中查找
			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是否需要进行类型验证,一般是不需要的 | 如果不是仅仅做类型检查则是创建 bean,这里需要进行记录
		if (!typeCheckOnly) {
			// 向容器标记指定的Bean是否已经被创建
			markBeanAsCreated(beanName);
		}

		try {
			//根据指定的Bean的名称获取其父级别的Bean的定义
			// 主要解决Bean继承子类和父类公共属性的问题,将存在 XML 配置文件的 GenericBeanDefinition 转换为 RootBeanDefinition
			// 如果指定 BeanName 是子的 Bean 的话同时合并父类的相关属性
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			//    如果存在依赖则需要递归实例化依赖的 bean
			String[] dependsOn = mbd.getDependsOn();
			//如果当前的Bean有依赖的Bean
			if (dependsOn != null) {
				for (String dependsOnBean : dependsOn) {
					if (isDependent(beanName, dependsOnBean)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
					}
					//把被依赖的Bean注册给当前的依赖的Bean 
					registerDependentBean(dependsOnBean, beanName);
					// 递归调用getBean()方法,获取当前的Bean的依赖的Bean
					getBean(dependsOnBean);
				}
			}

			// Create bean instance.
			// 创建单例模式的Bean的实例对象
			if (mbd.isSingleton()) {
				//这里使用了一个匿名的内部类创建Bean实例对象,并且注册给所依赖的对象
				sharedInstance = getSingleton(beanName, new ObjectFactory() {
					@Override
					public Object getObject() throws BeansException {
						try {
							//创建一个指定的Bean的实例对象,如果有父类继承,则合并子类和父类的定义
							// ObjectFactory核心的部分其实只调用了createBean的方法,所以我们还需要到createBean方法中追寻真理
							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.
							// 显示的从容器中单例模式的Bean缓存中清除实例对象
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				//获取给定的Bean的实例对象
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			//Ioc容器创建原型模式的Bean的实例对象
			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				// 原型模式(Prototype)每次都会创建一个新的对象
				Object prototypeInstance = null;
				try {
					//回调BeforePrototypeCreation()方法,默认的功能是在注册当前创建的原型对象
					beforePrototypeCreation(beanName);
					//创建指定的Bean的对象实例
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					//回调afterPrototypeCreation()方法,默认的功能是告诉Ioc容器不要再创建指定的Bean的原型对象
					afterPrototypeCreation(beanName);
				}
				//获取指定的Bean的实例对象
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}
			//如果要创建的对象既不是单例模式,也不是原型模式,则根据Bean定义资源中
			// 配置的生命周期范围,选择实例化Bean的合法方法,这种方法在WEb应用程序中
			//比较常用,如request,session,application等生命周期
			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
				}
				try {
					// 这里又使用了一个匿名的内部类,获取 一个指定的生命周期的实例
					Object scopedInstance = scope.get(beanName, new ObjectFactory() {
						@Override
						public Object getObject() throws BeansException {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						}
					});
					// 获取指定的Bean的实例对象
					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.
	//检查需要的类型是否符合 bean 的实际类型
	if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
		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;
}

AbstractBeanFactory.java

/**
 * 获取给定的Bean的实例对象,主要完成FactoryBean 的相关处理
 * 从这个代码中来看,其实这个方法并没有什么重要的信息,大多都是辅助的代码以及一些功能性的判断,而真正的核心代码去委托给了 getObjectFromFactoryBean
 * ,我们来看看 getObjectFromBeanInstance 中所做的工作
 *
 * 	 1. 对 FactoryBean 正确性的验证
 * 	 2.对非 FactoryBean 不做任何处理
 * 	 3.对 bean 进行转换
 * 	 4.将从 Factory 上解析 bean 的工作委托给 getObjectFromFactoryBean
 *
 * 5.3 从bean实例中获取对象
 * 在getBean方法中,getObjectForBeanInstance是个高频率的使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean
 * 总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean
 * ,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject()作为返回值
 *
 * 无论是从缓存中获取的bean还是通过不同的scope策略加载的bean都只是最原始的bean状态,并不是最终想要 的bean,举个例子来说,例如我们
 * 需要对工厂bean进行处理,那么这里得到的其实就是工厂的bean的初始化状态,但是我们 真正需要的工厂bean中定义的factory-method方法中返回的
 * bean,而getObjectForBeanInstance方法就是完成这个工作的
 */
protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
	// 如果指定的name是工厂相关的以(&为前缀)且 beanInstance 又不是 FactoryBean 类型则验证不通过
	if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
		throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
	}
	//  现在我们有了个bean 的实例,这个实例可能会是正常的 bean 或者是 FactoryBean
	//  如果是 FactoryBean 我们使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的 getObject 方法对应的实例,那么传入的 name 应该加入前缀 &
	if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
		//如果bean没有继承FactoryBean或者 名称包含& 符号  
		return beanInstance;
	}
	// 处理指定名称不是容器的解引用,或者根据名称获取Bean 实例对象是一个工厂Bean
	// 使用工厂Bean创建一个Bean 的实例对象
	// 加载 FactoryBean
	Object object = null;
	if (mbd == null) {
		// 尝试从缓存中加载 bean
		object = getCachedObjectForFactoryBean(beanName);
	}
	// 让Bean 工厂产生指定名称Bean的实例对象
	if (object == null) {
		// Return bean instance from factory.
		// 到这里已经里已经明确的知道 beanInstance 一定是一个 FactoryBean 类型
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// 如果从Bean 工厂生成的Bean 是单例模式,则缓存
		// Caches object obtained from FactoryBean if it is a singleton.
		// containsBeanDefinition检测 beanDefinitionMap 中也就是所有的已经加载的类中检测是否定义了 beanName
		if (mbd == null && containsBeanDefinition(beanName)) {
			// 从容器中获取指定名称的Bean的定义,如果继承了基类,则合并基类的相关的属性 |  将存储在 XML 配置文件中的 GenericBeanDefinition
			// 转换成 RootBeanDefinition,如果指定的是 beanName 是子的 bean 的话,同时会合并父类的相关的属性
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		// 如果从容器中得到了Bean定义信息,并且Bean定义信息不是虚构的
		// 则让工厂Bean产生Bean的实例对象
		// 是否用户定义的而不是应用程序本身定义的
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// 调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean()方法
		// 实现工厂Bean生产Bean实例对象的过程
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

FactoryBeanRegistrySupport.java

/**
 *	很遗憾,在这个代码中我们还是没有看到想要看到的代码,在这个方法里只做了一个事情,就是返回 bean ,如果是单例的,那就必需要保证全局
 *唯一,同时也因为是单例,所以不必重复创建,可以使用缓存 来提高性能,,也就是说已经加载的过就要记录下来以便下次复用,否则的话就直接获取 了
 * 在 doGetObjectFromFactoryBean  方法中我们终于看到了我们想要看到的方法,也就是说 object=factory.getObject(),是的,就是这句
 * 代码,我们历程犹如肃洋葱一样,一层一层的直到最内部的代码实现
 */
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
	// Bean工厂是单例模式,并且Bean工厂缓存中存在指定名称的Bean实例对象 | 如果是单例模式
	if (factory.isSingleton() && containsSingleton(beanName)) {
		// 多线程同步,以防止数据不一致
		synchronized (getSingletonMutex()) {
			// 直接从Bean工厂缓存中获取指定的名称的Bean实例对象
			Object object = this.factoryBeanObjectCache.get(beanName);
			// 如果Bean 工厂缓存 中没有指定名称的实例对象,则生产该实例对象
			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 (object != null && shouldPostProcess) {
						try {
							object = postProcessObjectFromFactoryBean(object, beanName);
						}
						catch (Throwable ex) {
							throw new BeanCreationException(beanName,
									"Post-processing of FactoryBean's singleton object failed", ex);
						}
					}
					// 将生产出来的实例对象添加到Bean 工厂缓存中
					this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
				}
			}
			return (object != NULL_OBJECT ? object : null);
		}
	}
	// 调用Bean 工厂获取对象方法生产指定Bean实例对象
	else {
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		if (object != null && shouldPostProcess) {
			try {
				// 调用 objectFactory 的后处理器
				object = postProcessObjectFromFactoryBean(object, beanName);
			}
			catch (Throwable ex) {
				throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
			}
		}
		return object;
	}
}

FactoryBeanRegistrySupport.java

/**
 * 调用Bean 工厂方法生产指定的 Bean 的实例对象
 */
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() {
					@Override
					public Object run() throws Exception {
							return factory.getObject();
						}
					}, acc);
			}
			catch (PrivilegedActionException pae) {
				throw pae.getException();
			}
		}
		else {
			// 直接调用 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);
	}

	// 创建出来的实例对象为null,或者因为单例对象正在创建而返回null
	if (object == null && isSingletonCurrentlyInCreation(beanName)) {
		throw new BeanCurrentlyInCreationException(
				beanName, "FactoryBean which is currently in creation returned null from getObject");
	}
	return object;
}

终于到了我们的核心方法,调用我们的 getObject 方法,返回了 bean 对象。
我们来总结一下。
1.对于 getBean 方法,如果传入的名字包含&,则直接返回 FactoryBean 本身,如果没有包含&,则直接调用 FactoryBean 的 getObject 方法。

本文git地址
https://github.com/quyixiao/spring_tiny/tree/master/src/main/java/com/spring_1_100/test_31_40/test32_factory_bean

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值