本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1.BeanFactory 与 ApplicationContext 的功能
1.1BeanFactory 与 ApplicationContext
/*
BeanFactory 与 ApplicationContext 的区别
*/
@SpringBootApplication
public class A01 {
private static final Logger log = LoggerFactory.getLogger(A01.class);
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
// 返回的就是spring容器:可配置的 ApplicationContext
// ConfigurableApplicationContext 是 ApplicationContext的子接口
// 通过option+command+U查看类图
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
/*
1. 到底什么是 BeanFactory
- 它是 ApplicationContext 的父接口
- 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现【组合】了它的功能
*/
// BeanFactory是ApplicationContext的一个成员变量
System.out.println(context);
}
}
- (1)到底什么是 BeanFactory
- 它是 ApplicationContext 的父接口
- 它才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能(BeanFactory是ApplicationContext的一个成员变量)
1.2BeanFactory 的功能 DefaultListableBeanFactory
command + f12 查看接口中的所有方法
-
(2)BeanFactory 能干点啥
- 表面上只有
getBean - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供(DefaultListableBeanFactory)
- 表面上只有
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
System.out.println(context);
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());
});
}
// 注册的2个bean
@Component
public class Component1 {
private static final Logger log = LoggerFactory.getLogger(Component1.class);
}
@Component
public class Component2 {
private static final Logger log = LoggerFactory.getLogger(Component2.class);
}
打印结果
component1=com.itheima.a01.Component1@4d8539de
component2=com.itheima.a01.Component2@3eba57a7
1.3ApplicationContext的功能
-
(3)ApplicationContext 比 BeanFactory 多点啥(扩展的功能主要体现在继承的4个父接口上)⭐️
- 多语言能力(国际化能力)
- 通配符匹配资源的能力
- 发布事件对象
- 环境信息
功能1:多语言能力
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
存在的未解决的问题
Exception in thread "main" org.springframework.context.NoSuchMessageException: No message found under code 'hi' for locale 'zh_CN'.
功能2:匹配资源的能力
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
打印的结果
URL [jar:file:/Users/cat/environment/repo/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/Users/cat/environment/repo/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/Users/cat/environment/repo/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]
功能3:环境信息
System.out.println(context.getEnvironment().getProperty("JAVA_8_HOME"));
System.out.println(context.getEnvironment().getProperty("JAVA_11_HOME"));
System.out.println(context.getEnvironment().getProperty("spring.messages.basename"));
打印的结果
/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home
messages://messages_zh.properties
功能4:发布事件(如实现用户注册和发布事件的解耦)
@EventListener
public void aaa(UserRegisteredEvent event) {
log.debug("{}", event);
log.debug("发送短信");
}
工作中的使用如下
总结一下
a. BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能
b. 又新学一种代码之间解耦途径