Skip to content

Commit ec41fe0

Browse files
committed
feat:模块装配
1 parent ae59eaa commit ec41fe0

21 files changed

+495
-5
lines changed

notes/笔记.md

Lines changed: 215 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ AutowireCapableBeanFactory的具体实现,它可以实现组件的自动装配
100100
**特点:**
101101

102102
- DefaultListableBeanFactory 是BeanFactory的 **最终默认实现**
103-
- DefaultListableBeanFactory会注册Bean的定义信息再创建Bean:DefaultListableBeanFactory实现
103+
- DefaultListableBeanFactory会注册Bean的定义信息再创建Bean:DefaultListableBeanFactory实现了 **`BeanDefinitionRegistry`**,它会利用这个接口 **注册Bean定义信息**。所以完整的Bean的管理是 **1、注册Bean的定义信息,2、完成Bean的创建和初始化动作**
104+
- DefaultListableBeanFactory不负责解析Bean定义文件
104105

106+
### XmlBeanFactory【了解】
105107

108+
在 SpringFramework 3.1 之后,`XmlBeanFactory` 正式被标注为**过时**,代替方案是: `DefaultListableBeanFactory + XmlBeanDefinitionReader` 更加符合单一职责
106109

107-
108-
109-
目前的关系:
110+
### BeanFactory体系关系图:
110111

111112
```mermaid
112113
classDiagram
@@ -167,21 +168,230 @@ ListableBeanFactory --> BeanFactory
167168

168169
https://c5id4ymctd.feishu.cn/wiki/EC38w0YyeiHj4PkkAvCceFbQnvB
169170

171+
## ApplicationContext
172+
173+
开发中推荐使用 ApplicationContext 而不是BeanFactory,因为ApplicationContext 扩展了很多功能
170174

175+
| Feature | `BeanFactory` | `ApplicationContext` |
176+
| :----------------------------------------------------------- | :------------ | :------------------- |
177+
| Bean instantiation/wiring —— Bean的实例化和属性注入 | Yes | Yes |
178+
| Integrated lifecycle management —— **生命周期管理** | No | Yes |
179+
| Automatic `BeanPostProcessor` registration —— **Bean后置处理器的支持** | No | Yes |
180+
| Automatic `BeanFactoryPostProcessor` registration —— **BeanFactory后置处理器的支持** | No | Yes |
181+
| Convenient `MessageSource` access (for internalization) —— **消息转换服务(国际化)** | No | Yes |
182+
| Built-in `ApplicationEvent` publication mechanism —— **事件发布机制(事件驱动)** | No | Yes |
171183

184+
## 1. ApplicationContext和它的上下辈们
172185

186+
**特点:**
173187

188+
- ApplicationContext 是 **中央接口**,最最核心,涉及一个重要概念: **重新加载**
174189

190+
- ApplicationContext组合多个功能接口
175191

176-
## ApplicationContext
192+
- 继承 `ListableBeanFactory` :具有访问应用程序组件的 Bean 工厂方法
193+
194+
- 继承 `ResourceLoader` 接口:以通用方式加载文件资源的能力
195+
196+
- 继承 `ApplicationEventPublisher` 接口:将事件发布给注册的监听器
197+
198+
- 继自 `MessageSource` 接口:解析消息的能力,支持国际化
199+
200+
- 从父上下文继承。在子容器中的定义将始终优先。例如,这意味着整个 Web 应用程序都可以使用单个父上下文,而每个 servlet 都有其自己的子上下文,该子上下文独立于任何其他 servlet 的子上下文。
201+
202+
> Application是层级结构的,但是这里描述的是**父子上下文****上下文包含容器,但不仅仅是容器。容器只负责管理bean,但是上下文包含动态增强,资源加载,事件监听机制等多方面的扩展功能**
203+
204+
- ApplicationContext负责部分回调注入:ApplicationContext它集成的几个接口
205+
206+
- `ResourceLoader``ResourceLoaderAware`
207+
- `ApplicationEventPublisher``ApplicationEventPublisherAware`
208+
- `MessageSource``MessageSourceAware`
209+
210+
### ConfigurableApplicationContext【掌握】
211+
212+
**ConfigurableBeanFactory** 类似,它给ApplicationContext提供了可的功能
213+
214+
**特点:**
215+
216+
- ConfigurableApplicationContext 提供了可配置的功能:提供了 `setParent``setEnvironment``addBeanFactoryPostProcessor``addApplicationListener` 等方法,都是可以改变 `ApplicationContext` 本身的方法。
217+
- ConfigurableApplicationContext只希望被启动和关闭:ConfigurableApplicationContext本身扩展了一些方法,但是它一般情况下不希望让咱开发者调用,而是只调用启动(refresh)和关闭(close)方法。注意这个一般情况是在程序运行期间的业务代码中,但如果是为了定制化 `ApplicationContext` 或者对其进行扩展,`ConfigurableApplicationContext` 的扩展则会成为切入的主目标。
218+
219+
### EnvironmentCapable【熟悉】
220+
221+
**capable** 是能力的意思,在这里解释为 **“携带/组合”** 更为合适。
222+
223+
> **在 SpringFramework 中,以 Capable 结尾的接口,通常意味着可以通过这个接口的某个特定的方法(通常是 `getXXX()` )拿到特定的组件。**
224+
225+
**特点:**
226+
227+
- ApplicationContext都具有 **EnvironmentCapable**的功能
228+
- `Environment` 是 SpringFramework 中抽象出来的类似于**运行环境****独立抽象**,它内部存放着应用程序运行的一些配置。
229+
- 基于 SpringFramework 的工程,在运行时包含两部分:**应用程序本身、应用程序的运行时环境**
230+
- ConfigurableApplicationContext可以获取ConfigurableEnvironment:可配置的ApplicationContext可以获取到可配置的Environment
231+
232+
### MessageSource【熟悉】
233+
234+
国际化:针对不同国家/地区,提供对应符合用户阅读的页面和数据
235+
236+
### ApplicationEventPublisher【熟悉】
237+
238+
ApplicationEventPublisher是任务发布器。ApplicationContext需要作为观察者模式中**广播器**的角色
239+
240+
### ResourcePatternResolver【熟悉】
241+
242+
资源解析器,**根据特定的路径去解析资源路径**
177243

244+
**特点:**
245+
246+
- ResourcePatternResolver是ResourceLoader的扩展:可以实现 **Ant**形式带有*号的路径解析
247+
- ResourcePatternResolver的实现方式有多种
248+
- ResourcePatternResolver支持的Ant路径模式匹配,例如:例如 `"/WEB-INF/*-context.xml"`
249+
- ResourcePatternResolver可以匹配类路径下的文件:可以匹配`classpath*:`
250+
251+
## 2. ApplicationContext的实现类们
252+
253+
### AbstractApplicationContext【掌握*
254+
255+
这个类是 `ApplicationContext` **最最最最核心的实现类,没有之一**。定义和实现了 **绝大部分应用上下文的特性和功能**
256+
257+
**特点:**
258+
259+
- AbstractApplicationContext只构建功能抽象,实现通用的上下文功能,让子类去实现一些具体功能
260+
- AbstractApplicationContext可以处理特殊类型的Bean:ApplicationContext能够处理一些特殊的Bean 比如 **后置处理器,监听器** 这些BeanFactory是不会区别对待的,但是ApplicationContext会
261+
- AbstractApplicationContext可以转化多种类型:`ApplicationContext` 实现了国际化的接口 `MessageSource` 、事件广播器的接口 `ApplicationEventMulticaster` ,那作为容器,它也会**把自己看成一个 Bean** ,以支持不同类型的组件注入需要。
262+
- AbstractApplicationContext 提供默认的加载资源策略:AbstractApplicationContext集成了DefaultResourceLoader。
263+
264+
> 提供生命周期的重要方法:refresh()
265+
266+
### GenericApplicationContext【熟悉】
267+
268+
**注解驱动的IOC容器**,已经是一个普通的类(非抽象类)了,它里面已经具备了 `ApplicationContext` 基本的所有能力了。
269+
270+
**重点:**GenericApplicationContext并不是集成了BeanFactory容器,而是组合了`BeanFactory`
271+
272+
**特点:**
273+
274+
- GenericApplicationContext借助BeanDefinitionRegistry处理特殊Bean:GenericApplicationContext因为实现了**`BeanDefinitionRegistry`**接口,可以注册bean,但是它底层还是用的 `DefaultListableBeanFactory` 执行 `registerBeanDefinition` 方法,说明它也没有对此做什么扩展。
275+
- GenericApplicationContext只能刷新一次:GenericApplicationContext只能刷新一次,BeanFactory是在`GenericApplicationContext`**构造方法中就已经初始化好**了,一旦构造好了就不能变更过了
276+
- GenericApplicationContext的替代方案是用xml:**注解驱动的 IOC 容器可以导入 xml 配置文件**,不过如果大多数都是 xml 配置的话,官方建议还是直接用 `ClassPathXmlApplicationContext` 或者 `FileSystemXmlApplicationContext` 就好。
277+
- GenericApplicationContext不支持特殊Bean定义的可刷新读取
178278

279+
### AbstractRefreshableApplicationContext【熟悉】
179280

281+
可刷新的ApplicationContext,和GenericApplicationContext最大的区别就是,AbstractRefreshableApplicationContext可以**被重复刷新**
180282

283+
**特点:**
284+
285+
- AbstractRefreshableApplicationContext支持多次刷新:每次都会创建一个新的 ****新的内部的 `BeanFactory` 实例****(也就是 `DefaultListableBeanFactory`
286+
- AbstractRefreshableApplicationContext刷新的核心是加载 `Bean的定义信息`:那它里面存放的 **Bean 定义信息应该是可以被覆盖加载的**,每次刷新时就应该重新加载 Bean 的定义信息,以及初始化 Bean 实例。
287+
- AbstractRefreshableWebApplicationContext额外扩展了Web环境的功能
288+
- 与普通的Application相比,WebApplicationContext额外扩展了与Servlet相关的部分,比如Request,ServletContext等
289+
- AbstractRefreshableApplicationContext几个重要的最终的实现类
290+
- 基于xml文件:`ClassPathXmlApplicationContext``FileSystemXmlApplicationContext`
291+
- 基于注解:`AnnotationConfigApplicationContext`
292+
293+
### AbstractRefreshableConfigApplicationContext【了解】
294+
295+
通篇就抽出来一句话:用于添加对指定配置位置的通用处理。由于它是基于 xml 配置的 `ApplicationContext` 的父类,所以肯定需要传入配置源路径,那这个配置的动作就封装在这个 `AbstractRefreshableConfigApplicationContext` 中了。
296+
297+
### AbstractXmlApplicationContext【掌握】
298+
299+
AbstractXmlApplicationContext就是`ClassPathXmlApplicationContext`的和`FileSystemXmlApplicationContext`的直接父类了
300+
301+
**特点:**
181302

303+
- AbstractXmlApplicationContext已具备了基本的全部功能
304+
- AbstractXmlApplicationContext有loadBeanDefinitions的实现:它组合了一个 `XmlBeanDefinitionReader`
182305

306+
### ClassPathXmlApplicationContext【掌握】
183307

308+
就是从classpath下加载xml配置文件的`ApplicationContext`
309+
310+
**特点:**
311+
312+
- ClassPathXmlApplicationContext 是一个最终的落地实现
313+
- ClassPathXmlApplicationContext使用Ant模式声明配置文件路径:比如:application-*.xml
314+
- ClassPathXmlApplicationContext解析的配置文件有先后之分:本工程resource目录下xml文件声明的bean会覆盖引入的jar包里面的xml文件里面同名的bean。
315+
- ApplicationContext可组合灵活使用:AbstractXmlApplicationContext 的本质是内部组合了`AbstractXmlApplicationContext`,所以除了使用ClassPathXmlApplicationContext外,我们还可以利用 `GenericApplicationContext` 或者子类 `AnnotationConfigApplicationContext` ,配合 `XmlBeanDefinitionReader` ,就可以做到注解驱动和 xml 通吃了。
316+
317+
### AnnotationConfigApplicationContext【掌握】
318+
319+
AnnotationConfigApplicationContext继承了`GenericApplicationContext`,所以只能刷新一次。它是一个最终落地实现。
320+
321+
**特点:**
184322

323+
- AnnotationConfigApplicationContext是一个最终落地实现:除了@Component,还有@Configuration相当于xml文件
324+
- AnnotationConfigApplicationContext解析配置的顺序有先后之分:
325+
326+
# 监听器
327+
328+
spring自定义监听器的步骤
329+
330+
- 自定义事件 :实现ApplicationEvent类
331+
332+
```java
333+
/**
334+
* 自定义事件
335+
*/
336+
public class RegisterSuccessEvent extends ApplicationEvent {
337+
RegisterSuccessEvent(Object source) {
338+
super(source);
339+
}
340+
}
341+
342+
```
343+
344+
- 自定义监听器:实现ApplicationListener或者使用 @EventListener注解
345+
346+
```java
347+
@Component
348+
public class EmailSenderListener {
349+
@EventListener
350+
public void onRegisterSuccessEvent(RegisterSuccessEvent event) {
351+
System.out.println("监听到用户注册成功,发送邮件中");
352+
}
353+
}
354+
355+
```
356+
357+
- 发布事件:实现ApplicationEventPublisherAware,采用才如注入的ApplicationEventPublisher进行发布
358+
359+
```java
360+
@Service
361+
public class RegisterService implements ApplicationEventPublisherAware {
362+
363+
ApplicationEventPublisher publisher;
364+
365+
public void register(String username) {
366+
System.out.println(username + "注册成功");
367+
publisher.publishEvent(new RegisterSuccessEvent(username));
368+
}
369+
370+
@Override
371+
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
372+
this.publisher = applicationEventPublisher;
373+
}
374+
}
375+
376+
```
377+
378+
# 模块装配
379+
380+
## @Import
381+
382+
- 可以导入配置类
383+
- **`ImportSelector` 的实现类**
384+
- `ImportBeanDefinitionRegistrar` 的实现类
385+
- 普通类
386+
387+
## ImportSelector接口
388+
389+
- 可以导入普通类 (可以筛选)
390+
- 可以导入配置类(可以筛选)
391+
392+
## ImportBeanDefinitionRegistrar接口
393+
394+
# 条件装配
185395

186396

187397

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.event.EventListener;
4+
import org.springframework.stereotype.Component;
5+
6+
@Component
7+
public class EmailSenderListener {
8+
@EventListener
9+
public void onRegisterSuccessEvent(RegisterSuccessEvent event) {
10+
System.out.println("监听到用户注册成功,发送邮件中");
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.event.EventListener;
4+
import org.springframework.stereotype.Component;
5+
6+
@Component
7+
public class MessageSenderListener {
8+
@EventListener
9+
public void onRegisterSuccess(RegisterSuccessEvent event) {
10+
System.out.println("监听到用户注册成功,发送站内短信");
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
4+
5+
public class RegisterApplication {
6+
7+
public static void main(String[] args) {
8+
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(
9+
"com.linkedbear.spring.my_test.event_diy");
10+
RegisterService registerService = applicationContext.getBean(RegisterService.class);
11+
registerService.register("王二麻子");
12+
}
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.ApplicationEventPublisher;
4+
import org.springframework.context.ApplicationEventPublisherAware;
5+
import org.springframework.stereotype.Service;
6+
7+
@Service
8+
public class RegisterService implements ApplicationEventPublisherAware {
9+
10+
ApplicationEventPublisher publisher;
11+
12+
public void register(String username) {
13+
System.out.println(username + "注册成功");
14+
publisher.publishEvent(new RegisterSuccessEvent(username));
15+
}
16+
17+
@Override
18+
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
19+
this.publisher = applicationEventPublisher;
20+
}
21+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.ApplicationEvent;
4+
5+
/**
6+
* 自定义事件
7+
*/
8+
public class RegisterSuccessEvent extends ApplicationEvent {
9+
RegisterSuccessEvent(Object source) {
10+
super(source);
11+
}
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.linkedbear.spring.my_test.event_diy;
2+
3+
import org.springframework.context.ApplicationListener;
4+
import org.springframework.context.event.ContextRefreshedEvent;
5+
6+
/**
7+
* 自定义监听器
8+
*/
9+
public class SmsSenderListener implements ApplicationListener<RegisterSuccessEvent> {
10+
11+
@Override
12+
public void onApplicationEvent(RegisterSuccessEvent event) {
13+
System.out.println("监听到用户注册成功,发送短信");
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.linkedbear.spring.my_test.event_quickstart;
2+
3+
import org.springframework.context.event.ContextClosedEvent;
4+
import org.springframework.context.event.EventListener;
5+
import org.springframework.stereotype.Component;
6+
7+
@Component
8+
public class ContextConfig {
9+
10+
@EventListener
11+
public void onContextClosed(ContextClosedEvent event) {
12+
System.out.println("ContextClosedApplicationListener监听到ContextClosedEvent事件!");
13+
}
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.linkedbear.spring.my_test.event_quickstart;
2+
3+
import org.springframework.context.ApplicationListener;
4+
import org.springframework.context.event.ContextRefreshedEvent;
5+
import org.springframework.stereotype.Component;
6+
7+
@Component
8+
public class DemoContextRefreshedApplicationListener implements
9+
ApplicationListener<ContextRefreshedEvent> {
10+
11+
@Override
12+
public void onApplicationEvent(ContextRefreshedEvent event) {
13+
System.out.println("ContextRefreshedApplicationListener监听到ContextRefreshedEvent事件!");
14+
}
15+
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.linkedbear.spring.my_test.event_quickstart;
2+
3+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
4+
5+
public class Main {
6+
7+
public static void main(String[] args) {
8+
System.out.println("初始化容器");
9+
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.linkedbear.spring.my_test.event_quickstart");
10+
System.out.println("容器初始化完成");
11+
applicationContext.close();
12+
System.out.println("IOC容器关闭");
13+
}
14+
}

0 commit comments

Comments
 (0)