- 👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家
- 📕系列专栏:Spring源码、JUC源码
- 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
- 🍂博主正在努力完成2023计划中:源码溯源,一探究竟
- 📝联系方式:nhs19990716,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬👀
容器接口
以一个SpringBoot项目启动来举例
public class Application{
public static void main(String[] args){
SpringApplication.run(Application.class);
}
}
当我们点击run进入到方法内部的时候
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
实际上是有返回值的,返回值类型是ConfigurableApplicationContext,而当打开其类图结构时会发现是这样的:
Ctrl + Alt + U(打开类图的方式)
可以看到ConfigurableApplicationContext 是一个子接口,ApplicationContext是一个父接口,而BeanFactory是ApplicationContext的父接口。
而打印ConfigurableApplicationContext 类型的返回值时,会发现,其beanFactory里面有一个singletionObjects
其实也就是说 在ConfigurableApplicationContext 加载完成,对应的beanFactory里面的singletionObjects就也加载完成了。这个就是ApplicationContext的一个很大的优势,实现了自动加载。
通过上图也可以看出,BeanFactory 与 ApplicationContext 并不仅仅是简单接口继承的关系, ApplicationContext 组合并扩展了 BeanFactory 的功能,如MessageSource 处理国际化资源的能力、ResourcePatternResolver 通配符匹配资源的能力(磁盘路径 类路径找到的文件)、ApplicationEventPublisher(发布事件对象)、EnvironmentCapable(读取Spring中的环境信息,环境变量)
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));
System.out.println("----------------------------------------------------------");
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
System.out.println("----------------------------------------------------------");
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
System.out.println("----------------------------------------------------------");
context.getBean(Component1.class).register();
@Component
public class Component1 {
private static final Logger log = LoggerFactory.getLogger(Component1.class);
@Autowired
private ApplicationEventPublisher context;
public void register() {
log.debug("用户注册");
context.publishEvent(new UserRegisteredEvent(this));
}
}
@Component
public class Component2 {
private static final Logger log = LoggerFactory.getLogger(Component2.class);
@EventListener
public void aaa(UserRegisteredEvent event) {
log.debug("{}", event);
log.debug("发送短信");
}
}
BeanFactory
当我们双击BeanFactory进入时,ctrl + f12发现:
发现表面上只有getBean,但实际上控制反转、基本的依赖注入,直至Bean的生命周期的各种功能,其实都由其实现类提供。
进入其实现类(ctrl + N)DefaultListableBeanFactory 发现 其impl 了 ConfigurableListableBeanFactory,而ConfigurableListableBeanFactory又impl了ListableBeanFactory。
比如说在代码里创建一个DefaultListableBeanFactory 对象 如下:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
注册一组配置进去
// bean 的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", beanDefinition);
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
此时打印输出 beanFactory.getBeanDefinitionNames() 发现只有config被注册进去了,所以也就说明了@Configuration并没有解析,beanFactory缺少了解析 @bean等注解的能力,功能并不完整。
于是应该加入 一些常用的后置处理器(主要是配置注解相关的配置)、BeanFactoryPostProcessor、BeanPostProcessor:
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.forEach(beanPostProcessor -> {
System.out.println(">>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
此时打印发现能够正常的将 bean1 bean2打印出来,也就代表着bean1 bean2被注册进去了。到了这里其实能够发现,现在BeanFactory 当我们把这些后置处理器都加上之后已经和 ApplicationContext很像了,但是还不够,在前面ApplicationContext 加载完成,beanFactory里面的singletionObjects就也加载完成了,而我们这里显然并不能做到预加载,还是需要 System.out.println(beanFactory.getBean(Bean1.class).getBean2()); 才能够进行懒加载,而ApplicationContext已经实现了预加载,那么就应该添加这个:
beanFactory.preInstantiateSingletons(); // 准备好所有单例
此时,就能够实现预加载,而此时,BeanFactory已经变得和ApplicationContext 基本一样了。
调用顺序
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
这句前面提到了其实是添加一些 注解相关的配置,进入查看找到
def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
其中分别是解析Autowired 和 Resource注解的
其实在代码中可以看到是有明显的先后顺序的,如果我们在stream中sort排序,那么实际上是比较的AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor里面的 getOrder方法
所以Autowired 和 Resource的顺序还是有讲究的。
ApplicationContext
基于ApplicationContext的扩展有很多,但是正如前面对比的那样,不仅不需要像BeanFactory那样 引入Bean后置处理器和BeanFactory后置处理器,而且还能预加载,每一个Bean都在ApplicationContext启动之后被初始化。
如下所示:
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("a02.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
<!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
<bean id="bean1" class="com.itheima.a02.A02.Bean1"/>
<!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
<bean id="bean2" class="com.itheima.a02.A02.Bean2">
<!-- 依赖注入, 建立与 bean1 的依赖关系 -->
<property name="bean1" ref="bean1"/>
</bean>
或者不使用配置类,使用注解的方式:
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
BeanFactory VS ApplicationContext
通过上面的分析,其实也就更能清晰的知道ApplicationContext强在哪里了:
- 自动的 BeanPostProcessor 注册。
- 自动的 BeanFactoryPostProcessor 注册。
- 方便的 MessageSource、ResourcePatternResolver、ApplicationEventPublisher、EnvironmentCapable实现类使用。
- ApplicationEvent 的发布与 BeanFactory 懒加载的方式不同,它是预加载,所以,每一个 bean 都在 ApplicationContext 启动之后实例化。