Spring源码剖析-BeanFactory和ApplicationContext(其一)

发布时间 2023-07-14 09:31:55作者: StormArcita

1.

在Spring中,BeanFactory和ApplicationContext是两种容器,它们之间的关系是怎样的?我们使用的是哪个?它们的底层原理是什么?

以一个SpringBoot的启动类为例:

package com.example.demo3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
    public class Demo3Application {

        public static void main(String[] args) {
           SpringApplication.run(Demo3Application.class, args);
        }

    }

 

SpringApplication.run(Demo3Application.class, args);生成的其实是一个ConfigurableApplicationContext类型的对象:

package com.example.demo3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
    public class Demo3Application {

        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(Demo3Application.class, args);
        }

    }

 

使用Ctrl+Alt+U查看ConfigurableApplicationContext的类图:

 

可以发现,ConfigurableApplicationContext是继承ApplicationContext的,而ApplicationContext则是继承BeanFactory的,而且同时又继承了一些其它接口,所以ApplicationContext又对BeanFactory做了功能上的扩展。

BeanFactory是什么?

  • 它是ApplicationContext的父接口
  • 它是Spring真正的核心容器,ApplicationContext实现(组合)了BeanFactory的功能

为什么说ApplicationContext组合了BeanFactory的功能?看一个例子:

package com.example.demo3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
    public class Demo3Application {

        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(Demo3Application.class, args);

            context.getBean("aaa");
        }

    }

 

getBean(String name)方法功能就是根据传入的name去Bean容器中找出与name同名的bean;Ctrl+Alt+左键点击getBean,进入实现类,发现这里ConfigurableApplicationContext是被AbstractApplicationContext实现了:

 

点进AbstractApplicationContext中,查看其实现的getBean方法:

public Object getBean(String name) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(name);
}

 

通过getBeanFactory获得一个BeanFactory,然后调用BeanFactory的getBean方法来完成操作,所以我们可以说ApplicationContext是组合了BeanFactory。

同时,BeanFactory还是ApplicationContext的成员变量,可以这样证明:

package com.example.demo3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
    public class Demo3Application {

        public static void main(String[] args) {
            ConfigurableApplicationContext context = SpringApplication.run(Demo3Application.class, args);

            System.out.println(context); //在这里添加断点!
        }

    }

 

第13行添加断点,点击调试:

 

发现context中确实是有beanFactory成员变量的。

而且在beanFactory成员变量中有一个

,这个就是Spring中单例bean存放的地方,Spring中的Bean都是单例的,包括我们自己创建的bean。

 

2.BeanFactory的功能

Ctrl+F12查看一个类的所有方法

 

containsBean 判断是否有该bean

getAliases 获得一个bean的别名

getBean 获得bean

...

单看BeanFactory中好像没什么东西,但我们要看它的实现类,实际上控制反转、基本的依赖注入、直至Bean的生命周期的各种功能,都由它的实现类DefaultListableBeanFactory实现:

DefaultListableBeanFactory的类图:

 

DefaultListableBeanFactory继承了一个叫做DefaultSingletonBeanRegistry的类,这个类中有一个私有成员变量singletonObjects管理了所有的单例对象:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

单例对象都存放在DefaultSingletonBeanRegistry中的singletonObjects中。

我们想拿到这个singletonObjects中的单例对象,但它又是私有的,我们可以通过反射拿到:

@SpringBootApplication
    public class Demo3Application {

        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            ConfigurableApplicationContext context = SpringApplication.run(Demo3Application.class, args);
            Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
            singletonObjects.setAccessible(true);
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
            map.forEach((k,v)->{
                System.out.println(k+"="+v);
            });
        }

    }

 

要理清楚这里类之间的关系:

ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); 拿到的是一个ConfigurableListableBeanFactory,ConfigurableListableBeanFactory是一个接口,这里通过调试或者直接System.out.println(beanFactory.getClass());可以看到beanFactory其实是ConfigurableListableBeanFactory的实现类DefaultListableBeanFactory类型的,而DefaultListableBeanFactory又继承了DefaultSingletonBeanRegistry,所以beanFactory中可以拿到DefaultSingletonBeanRegistry中的singletonObjects。

我们可以自己定义一个Component组件,然后在执行上面获取singletonObjects的代码,会发现我们自己定义的Component组件也被存入了singletonObjects中:

 未完待续...