第一讲、Spring之容器接口
文章内容根据黑马程序员Spring视频教程所写!!!
视频地址:点击这里
一、BeanFactory与ApplicationContext的关系
public class A01Application {
private static final Logger log = LoggerFactory.getLogger(A01Application.class);
public static void main(String[] args) {
// 容器对象
ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
/**
* 1.到底什么是BeanFactory
* - 它是ApplicationContext的父类
* - 它才是Spring的核心容器,主要的ApplicationContext的实现都【组合】了它的功能
*/
context.getBean("aaa");
System.out.println(context);
/**
* 2.BeanFactory能干点啥
* - 表面上只有getBean()
* - 实际上控制反转 基本的依赖注入 直至bean的声明周期的各种功能,都由它的实现类提供
*/
// 通过反射获取字段
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 该字段是private的
singletonObjects.setAccessible(true);
// 获取bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 得获取bean1工厂的单例bean
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
// 前提:手动创建了两个容器,component1和component2
map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
.forEach(e -> {
System.out.println(e.getKey() + "=" + e.getValue());
});
/**
* 3. ApplicationContext比BeanFactory多点啥
*/
// 处理国际化资源
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.US));
// 通配符匹配资源
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
// 获取环境变量
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
//发布事件
context.publishEvent(new UserRegisteredEvent(context));
}
}
通过查看ConfigurableApplicationContext的类图,发现ApplicationContext间接继承了BeanFactory。其中ApplicationContext直接继承的4个接口(图中黄色框框圈着的接口)组合了BeanFactory的功能,这四个接口的功能是我们经常使用的。
context.getBean
(“aaa”)`,我们点进getBean()的源码(ctrl+alt+鼠标左键),发现该方法并不是ConfigurableApplicationContext提供,而是通过BeanFactory提供的。
通过调试,我们观察context的内容
context下有beanFactory,beanFactory下有singletonObjects(存储单例bean)
二、BeanFactory功能
DefaultListableBeanFactory
我们主要来看一下BeanFactory实现类DefaultListableBeanFactory,这是最重要的实现类,下图是DefaultListableBeanFactory的类图(ctrl+alt+u)
我们点击DefaultSingletonBeanRegistry,然后按f4
,进入到DefaultSingletonBeanRegistry类
发现有一个对象singletonObjects,该对象存储的就是单例bean,bean名称与bean是映射关系。
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
.forEach(e -> {
System.out.println(e.getKey() + "=" + e.getValue());
});
代码执行后,控制台的打印:
三、ApplicationContext功能
1、处理国际化资源
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.US));
2、通配符匹配资源
这里的资源指的是磁盘路径或类路径下的文件。如果是file:META-INF/spring.factories
代表从磁盘路径下找;如果是classpath:META-INF/spring.factories
代表从类路径下找;如果是classpath*:META-INF/spring.factories代表从类路径下找,但是包含jar包。
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
3、读取系统环境变量或者spring环境变量
这里获取环境是不区分大小写的
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
4、发布事件对象
context.publishEvent()是ApplicationEventPublisher接口的方法
context.publishEvent(new UserRegisteredEvent(context));
通过发布事件可以解耦合,
/**
* @author Becant
* 2024-04-24-19:35
* @version 1.0.0
* 事件发布类
*/
public class UserRegisteredEvent extends ApplicationEvent {
/**
* 发布事件
* @param source 事件源,发布事件的对象
*/
public UserRegisteredEvent(Object source) {
super(source);
}
}
/**
* @author Becant
* 2024-04-24-18:49
* @version 1.0.0
* 容器
*/
@Component
public class Component1 {
private static final Logger log = LoggerFactory.getLogger(Component1.class);
// 要接收某个事件,必须加上@EventListener,参数要与发布事件的参数一样
@EventListener
public void receive(UserRegisteredEvent event) {
log.debug("{}", event);
}
}