
前言
最深刻了解一個框架的思想的方式,莫過于看源碼,本系列旨在于從Springboot底層源碼(Version - 2.6.6)出發(fā),一步步了解springboot是如何運行起來的。
從0-1了解SpringBoot如何運行(一):Environment環(huán)境裝配
從0-1了解SpringBoot是如何運行起來的(二):定制你的banner
從0-1了解Spring是如何運行起來的(三):Context預(yù)處理,為加載容器做準(zhǔn)備
在前述的文章中,我們主要了解了SpringBoot是如何實現(xiàn)配置文件的加載、context的創(chuàng)建、banner圖打印的流程。這次的話我們主要針對context中的refresh處理進(jìn)行學(xué)習(xí)和解析。
public ConfigurableApplicationContext run(String... args) {
......
refreshContext(context);
......
}
簡介
本章節(jié)我們主要針對BeanDefinition的加載以及BeanFactory后處理進(jìn)行學(xué)習(xí)。在展開講解源碼之前,我們需要先來了解一下這些概念。
BeanDefinition
BeanDefinition是一個描述 Bean的類實例,其其實是一個描述bean和修改bean信息的一個接口對象。如下是BeanDefinition的一個繼承類圖:

從類圖中可以看到,其繼承了BeanMetaDataElement和AttributeAccessor。前者是Bean的元數(shù)據(jù)的存儲對象,其source屬性保存的是Bean實例的最基礎(chǔ)的定義信息。而AttributeAccessor則是提供了對BeanDefinition的一些操作接口,包括獲取特定的屬性、移除特定屬性以及添加特定屬性的方法。
BeanDefinition在Spring中其實是一個相當(dāng)重要的概念。其就如同Bean對象的圖紙,需要生產(chǎn)什么樣子的Bean都由BeanDefinition來定義。 同時結(jié)合類圖來看,我們不難看到,BeanDefinition還有以下的一些能力:
- 標(biāo)記當(dāng)前的Bean的作用范圍;
- 定義當(dāng)前Bean的工廠Bean的名稱;
- 當(dāng)前Bean的初始化方法名稱;
- 當(dāng)前Bean是否支持懶加載
- ... ...
通過對BeanDefinition進(jìn)行加載并存儲到BeanDefinitionMap中,后續(xù)Spring才能依照這些對應(yīng)的“圖紙”生成出匹配的Bean實例對象。
BeanFactoryPostProcessor

BeanFactoryPostProcessor實際是用來處理BeanFactory的后置處理器。其生效的主要時間段是在Bean實例化之前。另外,BeanFactoryPostProcessor其實也是Spirng提供的一個鉤子,其可以讓你根據(jù)自己的實際情況修改Bean的定義屬性。 最常見的應(yīng)用就是我們的Bean中會有一些占位符,那么在Bean實例化之前這些占位符肯定是要被實際的配置參數(shù)填充的,這個填充的過程就是通過BeanFactoryPostProcessor的后置處理完成的。
源碼解析:
在了解了上述的基本內(nèi)容后,我們就可以從源碼角度對整個bean的加載過程進(jìn)行了解和分析了。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 對刷新做了一些初始化的設(shè)置
prepareRefresh();
// 更新對工廠的引用 并 獲取容器工廠
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 預(yù)先對BeanFactory進(jìn)行相應(yīng)的處理,如設(shè)置上下文的類加載器、默認(rèn)的Bean等
prepareBeanFactory(beanFactory);
try {
// 抽象類預(yù)留的hook方法,允許子類在標(biāo)準(zhǔn)的BeanFactory初始化后,再進(jìn)行初始化。(模版設(shè)計模式)
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//關(guān)鍵代碼:會在這里調(diào)用BeanFactory的后處理器來初始化BeanDefinition,BD會在這里被加載到BDMap中。
invokeBeanFactoryPostProcessors(beanFactory);
......
}catch (BeansException ex) {
...
}finally {
...
}
}
}
Refresh(代碼的整體結(jié)構(gòu)采用模版設(shè)計模式實現(xiàn),具體的實現(xiàn)由子類實現(xiàn)。由于Refresh部分的整體的代碼塊相對較長,且包含的內(nèi)容較多。因此,本期我們只針對invokeBeanFactoryPostProcessors()及其之前的代碼進(jìn)行查看。可以看到,在執(zhí)行invokeBeanFactoryPostProcessors()之前,Spring對相應(yīng)的工廠做了一些處理,主要包括
1、發(fā)送context刷新的事件;
2、更新工廠的引用數(shù)據(jù);
3、預(yù)處理工廠數(shù)據(jù),如設(shè)置累加載器,注入一些默認(rèn)的BeanDefinition等。
4、如果這里我們實現(xiàn)了預(yù)留的postProcessBeanFactory方法,那么還會執(zhí)行這個模版鉤子。
5、再次發(fā)送Bean初始化的事件
6、調(diào)用BeanFactory的后處理器。
這里我們跳過前面的幾個步驟,直接追入最關(guān)鍵的源代碼進(jìn)行查看:
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
// 判斷當(dāng)前是否為BeanDef注冊器
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}else {
regularPostProcessors.add(postProcessor);
}
}
//加載第一批次的BeanFactoryPostProcessor,并進(jìn)行調(diào)用(該批次的均實現(xiàn)了PriOrityOrdered.class類)
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//此處調(diào)用第一批次的BDF注冊處理器。(如configClassPostProcessor,作用是加載所有的ConfigClass的BeanDef)
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
//調(diào)用第二批次的BDF處理器(此處代碼中什么都沒做。。。因為沒有實現(xiàn)ordered的類 O。O)
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
//循環(huán)對第三批次的BDF處理器進(jìn)行調(diào)用,直到無處理器,這里主要是對尚未初始化的BD進(jìn)行占位符等信息的替換填充,
//eg. MapperScannerConfigurer會對mapper的基礎(chǔ)包路徑、作用域范圍進(jìn)行占位符的填充。
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//按照實現(xiàn)了PriorityOrder、Ordered和其余的分類方式將處理器分開
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 如果已經(jīng)處理,則跳過
}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,再次調(diào)用實現(xiàn)了priorityOrdered的Processor。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接下來再調(diào)用一次實現(xiàn)了ordered的Processor。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后調(diào)用所有其他的后處理器
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除掉所有的緩存數(shù)據(jù)信息
beanFactory.clearMetadataCache();
}
這部分的源碼其實較長,整塊代碼主要是針對于BeanFactoryPostProcessor的執(zhí)行進(jìn)行操作的。這里梳理了一下整塊代碼的執(zhí)行邏輯:
第一階段:加載完BD前,調(diào)用初始化前的BeanFactoryPostProcessor:
- 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如ConfigurationClassPostProcessor,負(fù)責(zé)加載beanFactory內(nèi)的BeanDef)
- 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。
- 執(zhí)行剩余的所有BeanFactoryPostProcessor類。(如MapperScannerConfigure,對mapper的基本包路徑、是否懶加載等進(jìn)行占位符替換。)
第二階段: 加載完BD后,調(diào)用非提前初始化的 BeanFactoryPostProcessor:
調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如PropertySourcesPlaceholderConfigurer,對所有的BeanDef的占位符進(jìn)行填充)
調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。(如DependsOnDatabaseInitializationPostProcessor,控制DB的依賴屬性)
執(zhí)行剩余的所有BeanFactoryPostProcessor類。
首先,根據(jù)整個加載流程,可以比較直觀的一點是,對于BeanFactory的處理,我們在某種程度上是可以控制其PostProcessor加載調(diào)用的先后順序,這個可以通過PriorityOrder、Ordered等注解進(jìn)行相應(yīng)的控制。
接著,我們主要對上述的BeanFactoryPostProcessor中比較重要的兩個處理器進(jìn)行展開分析和學(xué)習(xí):
ConfigurationClassPostProcessor
`org.springframework.context.annotation.ConfigurationClassPostProcessor`主要實現(xiàn)的功能是將各處的配置類及其對應(yīng)的Bean的BeanDefinition掃描到對應(yīng)的Factory 中。其執(zhí)行的地方在第一階段,加載的主要源代碼如下所示:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//獲取此時的候選BeanDef的名字
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果當(dāng)前沒有需要加載的配置類,則直接返回
if (configCandidates.isEmpty()) {
return;
}
// 根據(jù)對應(yīng)的@Order注解的值排序?qū)?yīng)的配置候選類
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 通過應(yīng)用上下文來檢測所有的自定義bean名稱的生成策略。
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
//如果環(huán)境配置為null,則生成一個標(biāo)準(zhǔn)的環(huán)境
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 生成一個配置類解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
parser.parse(candidates); // 對配置的候選類進(jìn)行解析,直到所有的配置類被解析完成,退出循環(huán)
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// 創(chuàng)建配置類BeanDefinition閱讀器
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//加載配置類BD
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
candidates.clear(); // 清空候選配置類
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
上述源代碼的主要工作流程如下所示:
1、因為整個類的主要功能其實是對配置的類進(jìn)行加載,那么首先肯定要獲取到哪些是我們當(dāng)前需要加載的類,即找到configCandidates(翻譯為:候選的配置)
2、因為Spring本身加載配置類,也是需要一個先后順序的,那么此時需要先根據(jù)@Order的方式來進(jìn)行排序。
3、因為beanDefinition本身的名字都是由BeanNameGenerator生成的,那么這時肯定需要找到哪個才是我們需要調(diào)用的Bean的名字的生成器,從而進(jìn)行后續(xù)BeanDef的名字的生成
4、實例化一個 ConfigurationClassParser ,從名字猜測,就是專門解析我們的配置類的,然后執(zhí)行parser.parse(candidates);對候選配置類進(jìn)行解析,在一開始的時候,beanDefinition里面除了那些約定的類,其實只有我們自己的啟動類了,而我們的啟動類也是有@Configuration的,所以一開始其實就是解析我們的啟動類。在解析我們的啟動類的時候,不難想象,application類底下肯定還是有許多依賴的類的(通常通過@ComponentScan掃描出來),那么自然也是需要對這些類進(jìn)行加載的。這里我簡單的畫了一下不同配置類之間的依賴關(guān)系:

其實一看就是一顆典型的多叉樹,那么對于多叉樹的遍歷,腦海中不由自主的其實會想到?;蜻f歸。實際上,Spring也是如此做的。這個流程的大致加載邏輯如下圖所示:

執(zhí)行完了`parser.parse(candidates);`,其實只是將Config類的BeanDefinition給加載了,但是其中可能還有其管理的Bean實例可能都還是沒有加載進(jìn)來的的,那么此時就需要執(zhí)行一次`this.reader.loadBeanDefinitions(configClasses);`對配置類管理的相關(guān)Bean進(jìn)行加載。
在解析啟動類之后,將解析出來的所有類再次減去已經(jīng)解析的類,就會得到下一批需要解析的啟動類,依次循環(huán)往返,直到解析完所有的類,那么此時加載就算完成了。
5、在加載完了所有的BeanDef后,會將元信息讀取工廠的緩存清除了。由此以來,整個配置類及其依賴的BeanDef的加載流程就宣告結(jié)束。
PropertySourcesPlaceholderConfigurer
對于beanDef內(nèi)占位符的替換,主要由*PropertySourcesPlaceholderConfigurer*實現(xiàn)。其主要的處理步驟如下所示:
1、依據(jù)當(dāng)前工廠的不同environment創(chuàng)建不同的propertyResolver。
2、對不同的propertyResolver設(shè)置占位符的前綴(prefix)、后綴(suffix)、以及變量的切分符(valueSeparator)。一般默認(rèn)會是"${"、"}"和":"
3、根據(jù)propertyResolver再創(chuàng)建出BeanDefinitionVisitor,用于對不同的bean進(jìn)行遍歷及變量替換。
替換變量邏輯中的關(guān)鍵的核心代碼如下所示:
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver) {
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
//獲取到所有已經(jīng)加載好的Bd
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (String curName : beanNames) {
// 首先判斷不是處理“自己”對應(yīng)的BD才會進(jìn)行處理
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try {
//關(guān)鍵代碼
visitor.visitBeanDefinition(bd);
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}
//在Spring2.5中會對Alias(同名屬性)也進(jìn)行更新
beanFactoryToProcess.resolveAliases(valueResolver);
//會將屬性值的處理器保存下來
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
}
執(zhí)行前:

執(zhí)行后:

總結(jié)
相比前幾章,本章從內(nèi)容來說,是Spring中相對關(guān)鍵關(guān)鍵的內(nèi)容,主要描述的是關(guān)于BeanDef的加載、BeanDef內(nèi)占位符的數(shù)據(jù)填充等。最后讓我們回過頭來,再次審視一次整個refresh()代碼執(zhí)行的邏輯流程:
1、發(fā)送context刷新的事件;
2、更新工廠的引用數(shù)據(jù);
3、預(yù)處理工廠數(shù)據(jù),如設(shè)置類加載器,注入一些默認(rèn)的BeanDefinition等。
4、如果這里我們實現(xiàn)了預(yù)留的postProcessBeanFactory方法,那么還會執(zhí)行這個模版鉤子。
5、再次發(fā)送Bean初始化的事件
6、調(diào)用BeanFactory的后處理器。
-
第一階段:加載完BD前,調(diào)用初始化前的BeanFactoryPostProcessor:
- 調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如ConfigurationClassPostProcessor,負(fù)責(zé)加載beanFactory內(nèi)的BeanDef)
- 調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。
- 執(zhí)行剩余的所有BeanFactoryPostProcessor類。(如MapperScannerConfigure,對mapper的基本包路徑、是否懶加載等進(jìn)行占位符替換。)
-
第二階段: 加載完BD后,調(diào)用非提前初始化的 BeanFactoryPostProcessor:
調(diào)用實現(xiàn)了PriorityOrder的BeanFactoryPostProcessor類。(如PropertySourcesPlaceholderConfigurer,對所有的BeanDef的占位符進(jìn)行填充)
調(diào)用實現(xiàn)了Ordered的BeanFactoryPostProcessor類。(如DependsOnDatabaseInitializationPostProcessor,控制DB的依賴屬性)
執(zhí)行剩余的所有BeanFactoryPostProcessor類。
歸納成流程圖,整個流程就可以描述成如下的形式:
