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中:
未完待续...
标签:ApplicationContext,context,BeanFactory,springframework,源码,ConfigurableApplicatio From: https://www.cnblogs.com/Noob-Green-Hand/p/17552793.html