第一讲:BeanFactory和ApplicationContext接口

BeanFactory和ApplicationContext接口

  • 1. 什么是BeanFactory?
  • 2. BeanFactory能做什么?
  • 3.ApplicationContext对比BeanFactory的额外功能?
    • 3.1 MessageSource
    • 3.2 ResourcePatternResolver
    • 3.3 EnvironmentCapable
    • 3.4 ApplicationEventPublisher
  • 4.总结


1. 什么是BeanFactory?

BeanFactory是ApplicationContext的父接口,是真正的Spring核心容器,主要的ApplicationContext实现都【组合】了他的功能。


2. BeanFactory能做什么?

首先先看一下BeanFactory的接口定义:
第一讲:BeanFactory和ApplicationContext接口_第1张图片

表面上只有getBean功能,实际上控制反转、基本的依赖注入、直至Bean的生命周期的各种功能,都由他的实现类提供,例如:DefaultListableBeanFactory

DefaultListableBeanFactory不仅仅实现了BeanFactory,还额外拓展了非常多的接口,例如:SingletonBeanRegistry(单例),其实现类中的私有成员变量DefaultSingletonBeanRegistry#singletonObjects,包含了所有的单例Bean对象。

接下来,我们可以试着获取到容器中所有的单例对象(因为是私有成员变量,所以需要通过反射来暴力破解)。核心代码如下:

Field field = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
field.setAccessible(true);
// 获取到BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> singletons = (Map<String, Object>)field.get(beanFactory);

第一讲:BeanFactory和ApplicationContext接口_第2张图片


3.ApplicationContext对比BeanFactory的额外功能?

第一讲:BeanFactory和ApplicationContext接口_第3张图片

从上图可以看出,ApplicationContext对比BeanFactory额外拓展了一些功能,主要是EnvironmentCapableMessageSourceApplicationEventPublisherResourcePatternResolver

下面,我们逐个分析这几个功能。

  • MessageSource:支持项目的国际化
  • ResourcePatternResolver:通过通配符来获取文件
  • EnvironmentCapable:获取系统变量或者应用中定义的变量
  • ApplicationEventPublisher:发布事件

3.1 MessageSource

在项目的资源目录下,创建一个Resouce Bundle
第一讲:BeanFactory和ApplicationContext接口_第4张图片

共包含3个文件,所有语言通用的messages.properties、中文、英文。

// 测试MessageSource接口的功能
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));

在这里插入图片描述

控制台分别输出了你好hello, Locale一般是浏览器发起请求时,会自动携带的,因此不需要在代码里面写死。

3.2 ResourcePatternResolver

ResourcePatternResolver可以通过通配符来获取文件,如下:

  • classpath: : 从第一个classpath中加载。
  • classpath*: : 从所有的classpath中加载。
  • file: : 从文件系统加载资源。
  • jar: : 用于从 jar 文件加载的 URL 前缀。
  • war: : 用于从 Tomcat 上的war文件加载的 URL 前缀。
// 测试ResourcePatternResolver的功能
Resource[] resources = context.getResources("classpath*:/META-INF/spring.factories");
Lists.newArrayList(resources).forEach(System.out::println);

可以发现,所有的spring.factories文件都被找到了。

在这里插入图片描述

3.3 EnvironmentCapable

可以获取到服务器上的变量或者应用中的变量。变量名称不区分大小写

// 测试EnvironmentCapable的功能
ConfigurableEnvironment environment = context.getEnvironment();
System.out.println("JAVA_HOME:" + environment.getProperty("java_home"));
System.out.println("Server port is: " + environment.getProperty("server.port"));

在我的电脑中配置的JAVA_HOME是大写的,这边写小写,依然可以读取到。

第一讲:BeanFactory和ApplicationContext接口_第5张图片

3.4 ApplicationEventPublisher

事件发布器是Spring中非常重要的一个机制,属于发布订阅模式。可以用来解耦业务,支持异步执行。


public class UserRegisteredEvent extends ApplicationEvent {

    /**
     * 用户手机号码
     */
    private String phone;

    public UserRegisteredEvent(Object source, String phone) {
        super(source);
        this.phone = phone;
    }
}

首先编写一个用户注册事件类,继承于ApplicationEvent, 有一个自定义的成员变量:phone

/**
 * 完成用户注册逻辑
 *
 * @Date 2023/8/20 11:30
 */
@Component
@Slf4j
public class Component01 {

    @Resource
    private ApplicationEventPublisher eventPublisher;

    public void handleUserRegistered() {
        log.info("用户注册~");
        // 发布用户已注册事件
        eventPublisher.publishEvent(new UserRegisteredEvent(this, "119"));
    }
}

Component01处理用户注册逻辑,并且发布了上述事件。

/**
 * 事件监听器
 *
 * @Date 2023/8/20 11:30
 */
@Component
@Slf4j
public class Component02 {

    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        log.info("发送短信了~");
    }
}

Component02由于handleUserRegistered方法上标注了@EventListener注解,并且方法的参数为UserRegisteredEvent,说明这个组件监听了该事件。就可以做后续的业务处理了。

// 测试ApplicationEventPublisher的功能
Component01 bean = (Component01) context.getBean("component01");
bean.handleUserRegistered();

最后,在main方法中模拟调用一下,结果如下:

在这里插入图片描述


4.总结

BeanFactory和ApplicationContext并不仅仅是简单的接口继承关系,ApplicationContext组合并扩展了BeanFactory的功能。

你可能感兴趣的:(Spring源码学习,java,开发语言,spring,springboot)