目录
本文章向大家介绍Spring读书笔记——bean创建(上),主要内容包括从getBean说起、AbstractBeanFactory、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
通过《Spring读书笔记——bean加载》和《Spring读书笔记——bean解析》,我们明白了两件事。
我们经常使用下面的方式实现先加载xml文件,然后获取相应的bean实例
- BeanFactory beanFactory = new ClassPathXmlApplicationContext("application-context.xml");
- TestBean testBean = beanFactory.getBean("testBean");
显然,我们是通过getBean方法获取到的Bean实例,该方法是接口BeanFactory中定义的一个方法。具体实现在另外一个抽象类中,就是我们一会要说到的AbstractBeanFactory。
该抽象类集成了FactoryBeanRegistrySupport并实现了ConfigurableBeanFactory接口(该接口间接实现了接口BeanFactory)
通过上面的区块注释以及提供的方法getBean,我们一眼就看出其余BeanFactory的密切关系。
getBean
该方法非常简单,只是调用了一个函数,真正的实现都在doGetBean方法中了。代码实现有点长,但是我们还是得静下心来看看他到底做了哪些工作。
- protected
T doGetBean( - final String name, final Class
requiredType, final Object[] args, boolean typeCheckOnly) - throws BeansException {
-
- final String beanName = transformedBeanName(name);
- Object bean;
-
- // Eagerly check singleton cache for manually registered singletons.
- 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 + "'");
- }
- }
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }
-
- else {
- // Fail if we're already creating this bean instance:
- // We're assumably within a circular reference.
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
-
- // Check if bean definition exists in this factory.
- BeanFactory parentBeanFactory = getParentBeanFactory();
- 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);
- }
- }
-
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
-
- 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 dependsOnBean : dependsOn) {
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
-
- // Create bean instance.
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory
- public Object getObject() throws BeansException {
- try {
- 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 = 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 '" + scopeName + "'");
- }
- try {
- Object scopedInstance = scope.get(beanName, new ObjectFactory
- 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);
- }
- }
- }
归一化beanName 如果看了前面两篇文章,这里你就知道beanName就是注册到Spring容器中的bean的名称,具体来说就是放入BeanDefinitionMap中的一个键值对的key。 那么这里有什么好转换处理的呢。 我们看下transformedBeanName的具体实现
- public static String transformedBeanName(String name) {
- Assert.notNull(name, "'name' must not be null");
- String beanName = name;
- while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
- beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
- }
- return beanName;
- }
没错,做了一个断言处理,通过对于一种FactoryBean形式的bean做了处理。从FactoryBean这个命名就知道他是一种bean(不是病),*有关FactoryBean的介绍以及使用可以参看博文:http://blog.csdn.net/is_zhoufeng/article/details/38422549*,区别于BeanFactory(他是一个bean工厂,用于生产bean)。FactoryBean这种在注入bean的时候会在beanName前添加一个"&"修饰符,所以这里需要做归一化处理。
尝试从缓存中加载单例bean Object sharedInstance = getSingleton(beanName); 该方法就是实现从缓存中获取单例bean。 对于单例,应该都不陌生,单例bean,单例模式等等说的都是一个意思——一个东西只有一份。
bean实例化 假设我们从缓存中得到了bean,但是这还不是bean的最终状态,可以认为这只是一个引用,要获得真正的bean实例,我们还需要看下getObjectForBeanInstance方法。
原型模式的循环依赖检查 这里引用下上面提供有关循环依赖的链接中比较重要的内容
spring循环依赖的情况 1.构造器注入属性依赖(A B两个对象都使用构造方法,注入依赖的属性) 无论是单例,还是原型对象,只要是通过构造器注入的属性依赖,都会报错,循环依赖错误 org.springframework.beans.factory.BeanCurrentlyInCreationException: 原因:试想,构造器是创建对象的入口方法,构造的时候都循环依赖了,我这个对象压根就创建不了啊。那肯定是无法解决的,大罗神仙也无能为力。 2.setter方法注入属性依赖 这个spring完美解决了,支持这种循环依赖 原理:创建对象A的时候,先通过无参构造方法创建一个实例,此时属性都是空的,但是对象引用已经创建出来,然后把A的引用提前暴露出来。然后setter B属性的时候,创建B对象,此时同样通过无参构造方法构造然后将对象引用暴露出来。接着B执行setter方法,去池中找A,能找到A(因为此时A已经暴露出来,有指向改对象的引用了),这么依赖B就构造完成,也初始化完成,然后A接着初始化完成。---循环依赖就这么解决了 3.原型对象的属性依赖(当然指的是通过setter方法注入依赖) 这个spring也无能为力,因为是原型对象,A创建的时候不会提前暴露出来,所以,每次都是要创建,创建的时候,发现有相同的对象正在创建,同样报错,循环依赖错误,同第一种情况类似。
我们知道对于单例默认的循环依赖,我们是可以解决的,但是对于原型类型的循环依赖,我们没有办法解决,所以这里通过对于原型bean的检查适时抛出异常。
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
检测parentBeanFactory 顺着代码的逻辑,很自然的来到了从parentBeanFactory中加载Bean的模块。当在缓存中没有加载到Bean的时候,我们就会从parentBeanFactory中试试。
转换为RootBeanDefinition 前两篇,我们介绍了从xml标签到BeanDefinition的转变,这里我们需要将GenericBeanDefinition转为RootBeanDefinition,这是处于后面的处理是一致对于RootBeanDefinition处理考量的。
解决bean依赖的问题
- // Guarantee initialization of beans that the current bean depends on.
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (String dependsOnBean : dependsOn) {
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
从注释就可以知道,这块主要是解决在初始化一个bean的时候,这个bean依赖了其他的bean,所以需要在创建之前先初始化依赖的bean。
对于scope的处理以及对于类型转换的处理 后面剩下的代码主要是对于Spring中不同scope的处理,比如singleton、prototype、request、session等等。
上面就是getBean这一抽象层次上关于如何创建bean的详细过程,下面对于其中一些部分做详细解释。
等等,写着写着发现后面的点还是有点多,一篇恐怕撑不住了,还是分上下集吧~~~