Spring源码解析-getBean如何获取Ioc容器中的bean

在Spring框架中,主要是要IOC容器和AOP切面两块,然而从IOC容器中如何获取bean也对我们而言也是可以来学习解析的。

一、解读getBean的背景

  在工作中,一次通过从IOC容器中获取通过继承FactoryBean接口的类,发现在对注入后的类名添加&与不添加&的区别很大,在添加&的情况下,获取的是当前继承FactoryBean接口的类;在不添加&的情况下,获取的是当前继承FactoryBean接口的类中通过getObject()返回的类对象。
  因此引起了我对getBean的源码探讨,看看Spring框架中究竟是如何来获取继承FactoryBean接口的类的bean。

二、简单代码示例

  由于工作中的代码太过繁琐,同时也涉及到一些非必要的东西(呵呵,大家应该懂得),所以我通过简单的示例来通过继承FactoryBean接口完成IOC的注入,然后在后面的源码解读中来理解getBean方法(本篇文章主要是讲解getBean方法,由于getBean依赖通过继承FactoryBean接口完成IOC的注入的bean来获取,所以就在这部分来简单示例)。

1、pojo类
作为后面注入到IOC容器,需要通过getBean获取的对象

package com.cyw.demo.bean;

public class Girl {

}

2、基于FactoryBean接口继承的类
通过继承FactoryBean接口,实现getObject()获取Girl的对象。

package com.cyw.demo.config;

import org.springframework.beans.factory.FactoryBean;

import com.cyw.demo.bean.Girl;

public class DemoFactoryBean implements FactoryBean<Girl> {

    public Girl getObject() throws Exception {
        return new Girl();
    }

    public Class getObjectType() {
        return Girl.class;
    }
}

3、配置类
通过配置来注入DemoFactoryBean类。

package com.cyw.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DemoConfig {
    @Bean
    public DemoFactoryBean demoFactoryBean() {
        return new DemoFactoryBean();
    }
}

4、测试类

package maven_spring;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cyw.demo.config.DemoConfig;

public class DemoTest {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(DemoConfig.class);

        Object bean1 = app.getBean("demoFactoryBean");
        System.out.println(bean1);

        Object bean2 = app.getBean("&demoFactoryBean");
        System.out.println(bean2);
    }
}

通过只是test()方法,输出bean1和bean2变量的值。
这里写图片描述
发现bean1是Gril的实例对象,bean2是DemoFactoryBean的实例对象。

三、getBean()的源码解析

  现在应该是激动人心的时刻了,因为研究完getBean()的源码,就能很清楚的认识到上述示例中为什么在有没有添加&,输出的两个对象是不同了。
1、先上时序图
源码是基于5.0.6.RELEASE版本,大家可以随自己的意愿来选择
Spring源码解析-getBean如何获取Ioc容器中的bean_第1张图片

2、解析时序图
1)client为我们访问IOC容器,获取Bean

public class DemoTest {
    @Test
    public void test() {
        ApplicationContext app = new AnnotationConfigApplicationContext(DemoConfig.class);

        Object bean1 = app.getBean("demoFactoryBean");
        System.out.println(bean1);

        Object bean2 = app.getBean("&demoFactoryBean");
        System.out.println(bean2);
    }
}

2)通过getBean来进入调用的类AbstractBeanFactory.class
此处的源码只基于Object bean2 = app.getBean(“&demoFactoryBean”);来讲解,如果大家有兴趣,可以研究下Object bean1 = app.getBean(“demoFactoryBean”);
现在继续进入正题:
在AbstractBeanFactory.class类中getBean方法

@Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

3)doGetBean(name, null, null, false);方法
调用 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

4)进入AbstractAutowireCapableBeanFactory.class

@Override
    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

        String currentlyCreatedBean = this.currentlyCreatedBean.get();
        if (currentlyCreatedBean != null) {
            registerDependentBean(beanName, currentlyCreatedBean);
        }

        return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd);
    }

5)调会AbstractBeanFactory.class的getObjectForBeanInstance方法
主要看这段代码 判断当前类是否继承FactoryBean或者beanName是否有&前缀

if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
            return beanInstance;
        }

6)isFactoryDereference在BeanFactoryUtils.class类中,判断当前beanName是否有&前缀

public static boolean isFactoryDereference(@Nullable String name) {
        return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    }

通过上述代码的调用后会返回true,这样就会直接返回当前的beanInstance(在第5步)
关于Object bean1 = app.getBean(“demoFactoryBean”);这段对应的源码,是在上述的基础上继续深入即可。

Spring源码解析-getBean如何获取Ioc容器中的bean_第2张图片
扫描关注:全栈工程师成长记
一个可以交流的平台,目的是为了做一个影响最有影响力的人的平台。

你可能感兴趣的:(Spring)