BeanFactory
和ApplicationContext
的区别和联系
什么是BeanFactory
?
首先我们常用的启动类中的 SpringApplication.run(DemoApplication.class, args);
返回的就是ConfigurableApplicationContext
,他是继承BeanFactory
的,也就是spring
容器对象。下面是ConfigurableApplicationContext
的类图 【打开类图的快捷键为 ctrl + alt + u
】
代码:
public static void main(String[] args) {
// 返回的就是spring容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
System.out.println(run);
}
说明:
BeanFactory
是spring
的核心容器,主要的ApplicationContext
实现(或者说组合)了他的功能。
BeanFactory
的实现类为DefaultListableBeanFactory
,光看BeanFactory
里面可能我们熟悉的只有getBean
方法,但是控制反转,基本的依赖注入都是在实现类中完成的。
BeanFactory
能干点啥?
其实主要定义了关于获取
Bean
的方法
BeanFactory
的主要实现类是DefaultListableBeanFactory
管理单例类的实现类为DefaultSingletonBeanRegistry
,在DefaultSingletonBeanRegistry
中所有的单例对象都保存在一个ConcurrentHashMap
中
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
这里可以通过反射获取到singletonObjects
来观察其中的内容。
如果使用注解,将类交给Spring容器进行管理,那么在下面打印的键值对中,你也可以看到对应的类。
public static void main(String[] args) throws Exception {
// 返回的就是spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.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);
/**
* 所有注入到spring容器中的类都能获取到,可以自定义类查看
*/
map.forEach((k, v) -> {
System.out.println(k + " = " + v);
});
}
ApplicationContext
接口扩展了啥?
// 国际化【翻译】
context.getMessage("hi", null, Locale.US);
context.getMessage("hi", null, Locale.CANADA);
// 读取配置文件的
// class path resource [application.properties]
Resource resource = context.getResource("classpath:application.properties");
System.out.println(resource);
// classpath*
Resource[] resource1 = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource2 : resource1) {
System.out.println(resource2);
}
// 结果为
//URL [jar:file:/D:/maven/apache-maven-3.6.3/resp/org/springframework/boot/spring-boot/2.3.7.RELEASE/spring-boot-2.3.7.RELEASE.jar!/META-INF/spring.factories]
//URL [jar:file:/D:/maven/apache-maven-3.6.3/resp/org/springframework/boot/spring-boot-autoconfigure/2.3.7.RELEASE/spring-boot-autoconfigure-2.3.7.RELEASE.jar!/META-INF/spring.factories]
//URL [jar:file:/D:/maven/apache-maven-3.6.3/resp/org/springframework/spring-beans/5.2.12.RELEASE/spring-beans-5.2.12.RELEASE.jar!/META-INF/spring.factories]
// 获取系统配置信息的
System.out.println(context.getEnvironment().getProperty("java_home"));// D:\jdk
System.out.println(context.getEnvironment().getProperty("spring.application.name"));// demo
事件发布器:【比较有趣】
发送事件的方式
context.publishEvent(new UserEvent(context));
定义事件发送类
public class UserEvent extends ApplicationEvent {
public UserEvent(Object source) {
super(source);
}
}
定义事件接受类
方法名任意,但参数必须为想要接收的事件的类型,可以同时定义多个,发送的时候,是广播的形式,所有的接收类都会收到这个事件。
@Component
public class Component1 {
@EventListener
public void aaa(UserEvent event){
System.out.println("我收到事件了");
}
}
@Component
public class Component2 {
@EventListener
public void aaa(UserEvent event){
System.out.println("我收到事件了222222");
}
}
那么事件具体有什么用呢?
如果在用户注册动作中,在用户注册完毕之后,想要发送一个邮件,或者短信,这时候就可以使用事件的方式。
结合Spring
技术内幕来补充
1、对于Spring
的具体IoC
容器实现来说,它需要满足的基本特性是什么呢?它需要满足BeanFactory
这个基本的接口定义。
可想而知
BeanFactory
继承树等级是最高的,同时也是最基础的。
2、在Spring
提供的基本IoC
容器的接口定义和实现的基础上,Spring通过定义BeanDefinition
来管理基于Spring
的应用中的各种对象以及他们之间的相互依赖关系。BeanDefinition
抽象了我们对Bean的定义,是让容器起作用的主要数据类型
这里的
BeanDefinition
按照书中的解释,可以这么理解,如果Spring容器可以看作是各式各样的水桶,那么BeanDefinition
就是水桶中的水。也就是水桶发挥作用的根本。
3、计算机中所有的功能都是建立在通过数据对现实进行抽象的基础上进行的。
虽然这句话在书中仅仅是作为铺垫,但是在学习设计模式的时候,我就深有感触,在设计模式中,你会发现,这就是我们生活中的例子,只不过前辈们依靠编程语言的特性和计算机设计思想总结出了23种设计模式。但设计模式的难度在于,没有一定的开发经验,或者没有经历过这种场景的,有时候很难理解。推荐黑马的设计模式,讲的很透彻
本文是通过黑马程序员的spring5
底层原理视频学习总结的,包含一些个人看法,总结了一些Spring技术内幕
书籍中的关键语句。如有错误,欢迎指正。