首页 > 编程语言 >Spring源码剖析-BeanFactory和ApplicationContext(其一)

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

时间:2023-07-14 09:35:19浏览次数:30  
标签:ApplicationContext context BeanFactory springframework 源码 ConfigurableApplicatio

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

相关文章

  • 【Spring Security】的RememberMe功能流程与源码详解
    相关课程前言今天我们来聊一下登陆页面中"记住我"这个看似简单实则复杂的小功能。如图就是某网站登陆时的"记住我"选项,在实际开发登陆接口以前,我一直认为这个"记住我"就是把我的用户名和密码保存到浏览器的cookie中,当下次登陆时浏览器会自动显示我的用户名和密码,就不用我再次......
  • 实战:单点登录的两种实现方式,附源码
    相关课程最近工作有点忙,好久没更新文章了,正好这两天在整理单点登陆相关的文档,今天趁着小孩睡着了......
  • StarRocks Segment源码阅读笔记--SegmentIterator创建
    StarRocks中要读取Segment中的数据,需要先创建SegmentIteratorStatusOr<ChunkIteratorPtr>Segment::_new_iterator(constSchema&schema,constSegmentReadOptions&read_options){DCHECK(read_options.stats!=nullptr);//tryingtoprunethecurrentse......
  • ArrayList源码阅读
    ArrayList源码分析ArrayList简介ArrayList的底层是数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加ArrayList实例的容量。这可以减少递增式再分配的数量。ArrayList继承于AbstractList,实现......
  • 视频直播源码,搜索页面布局(Wrap组件)
    视频直播源码,搜索页面布局(Wrap组件)classLayoutDemoextendsStatelessWidget{ constLayoutDemo({Key?key}):super(key:key); @override Widgetbuild(BuildContextcontext){  returnPadding(   padding:constEdgeInsets.all(10),   child:W......
  • 直播软件源码,Flutter中导航栏和状态栏设置成透明
    直播软件源码,Flutter中导航栏和状态栏设置成透明一、Flutter透明状态栏设置 import'package:flutter/material.dart';//导入对应的文件import'package:flutter/services.dart';   voidmain(){ //配置透明的状态栏 SystemUiOverlayStylesystemUiOverlayStyle=co......
  • SVN 签出源码 Struts Spring Hibernate
    SVN签出源码StrutsSpringHibernate很多优秀的开源项目已经提供SVN源码签出了,无论是解疑还是学习,都是一大幸福之事啊!Apache的SVN库,强烈推荐!http://svn.apache.org/repos/asf/里面不但有Struts的源码,还有著名的Apachejakartaproject相当好的WebUI框......
  • 云开发校园微社区-二手交易兼职交友微信小程序源码
     源码说明:云开发校园微社区微信小程序开源源码,这是一款云开发校园微社区-二手交易_兼职_交友_项目微信小程序开源源码,可以给你提供快捷方便的校园生活,有很多有趣实用的板块和功能,如:闲置交易、表白交友、疑问互答、任务兼职、相约学习、失物招领、趣事分享等。在发布栏目可以......
  • Java面试高频技术线程池,源码笔记答案全纪录
    有一定的java基础(线程),尤其是正要或正准备找工作的童鞋如果想在众多面试者中脱颖而出,你就需要多准备一些知识点,多刷一些面试题。而对于企业而言,有这么多的选择那我们就提高面试门槛,可能我需要的仅仅是CRUD的初中级,但我也希望你能了解JVM、多线程、Spring源码、Sql优化、分布......
  • 树莓派人脸识别系统-计算机毕业设计源码+LW文档
    中文摘要计算机技术的发展推动了经济的发展,如今几乎所有的企业都离不开计算机软件,物业单位更是如此。在信息技术不断完善下,物业单位作为人们日常生活不可或缺的组成部分,发挥着重要的作用。然而,随着小区人员的增加,小区门禁管理繁琐,效率低下、进出等待时间长、满意度不高,阻碍了小区......