前文傳送門:
本文內容:
AbstractApplicationContext#refresh
前部分的一點小內容BeanFactoryPostProcessor
呼叫過程詳解mybatis
是如何使用本節知識整合spring的?
正文:
在Spring中,一共分為BeanFactoryPostProcessor
和BeanPostProcessor
兩類後置處理器,他們主要的職責如下:
BeanFactoryPostProcessor
:負責beanClass
到beanDefinition
的過程,包括但不限於尋找合適的beanClass
,建立beanDefinition
,修改beanDefinition
,將beanDefinition
註冊到BeanFactory
中BeanPostProcessor
:負責beanDefinition
到bean
的過程,包括但不限於bean
的屬性賦值,初始化
本次主要分析BeanFactoryPostProcessor
的呼叫過程,下面是BeanFactoryPostProcessor
呼叫過程的大體流程圖,也是本文想要表述的大概內容,原圖連結: BeanFactoryPostProcessor呼叫過程
refresh的前半段流程
// 啟動前的準備工作
prepareRefresh();
// 由於web專案中並不會先引入DefaultListableBeanFactory,在這裡通知子類重新整理BeanFactory
// 而我們是使用new AnnotationConfigApplicationContext()的方式,就是直接返回之前引入的DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 準備工作,給DefaultListableBeanFactory填充屬性
prepareBeanFactory(beanFactory);
// 留於子類呼叫的擴充套件方法
postProcessBeanFactory(beanFactory);
// 呼叫實現BeanFactoryPostProcessor的後置處理器,
// 其實就是我們在new AnnotatedBeanDefinitionReader時註冊的解析配置類的後置處理器ConfigurationClassPostProcessor
// 這裡會解析配置類以及處理解析配置類後所引入的所有BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 註冊上一步解析出來的所有的BeanPostProcessor
// 註冊邏輯和上一步大致相同,PriorityOrdered-> Ordered -> 普通的
registerBeanPostProcessors(beanFactory);
prepareRefresh
// 設定容器狀態
this.closed.set(false);
this.active.set(true);
prepareBeanFactory
// 新增一個ApplicationContextAwareProcessor,用於bean初始化前呼叫一系列的Aware介面回撥
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 用於處理實現ApplicationListener介面的bean,bean初始化後新增監聽
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
invokeBeanFactoryPostProcessors(重點)
此方法將解析配置類以及處理解析配置類後所引入的所有BeanFactoryPostProcessor
溫馨提醒:內容較多,還請耐心閱讀~
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//由於之前註冊的都是BeanDefinition,此時還並沒有生產任何的BeanFactoryPostProcessor,所以getBeanFactoryPostProcessors是空的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}
invokeBeanFactoryPostProcessors
前部分主要是尋找ConfigurationClassPostProcessor並將它例項化
//放置已處理的beanName
Set<String> processedBeans = new HashSet<>();
//放置常規的後置處理器,就是隻實現了BeanFactoryPostProcessor介面的
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//放置實現了BeanDefinitionRegistryPostProcessor介面的,之前我們註冊的後置處理器中只有ConfigurationClassPostProcessor實現了
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//放置當前的RegistryProcessors
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//查詢實現了BeanDefinitionRegistryPostProcessor介面的BeanName,其實就只有一個ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//ConfigurationClassPostProcessor同樣實現了PriorityOrdered介面
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//注意這裡呼叫了getBean方法,生產了ConfigurationClassPostProcessor,放到currentRegistryProcessors集合中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//將生產出來的後置處理器放到集合中
registryProcessors.addAll(currentRegistryProcessors);
接下來就開始呼叫ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
//呼叫ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
//迴圈BeanDefinitionRegistryPostProcessor進行呼叫
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
postProcessBeanDefinitionRegistry
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//放置候選配置類
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//遍歷之前註冊的所有bean定義,找到其中的配置類,其實就是我們自己傳進來的配置類
for (String beanName : candidateNames) {
//...省略校驗過程...
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//檢查是否是有@Configuration註解的BeanDifinition -> full型別的配置類 -> 會把配置類替換成動態代理類
//或者該類包含@Component @ComponentScan @Import @ImportResource @Bean 註解的其中之一 -> lite型別的配置類 -> 不會替換成動態代理類
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//....省略片段....
//例項化一個配置類解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
do {
//解析配置類
parser.parse(candidates);
parser.validate();
//parser.getConfigurationClasses()就是拿到剛剛解析完放到map中的配置類
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//這裡處理@Import匯入的beanDefintion和配置類中的@Bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//以下邏輯是找出未解析的配置類,如@Bean和ImportBeanDefinitionRegistrar所引入的
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);
//將是配置類並且沒有解析過的BeanDefinition放到候選集合中繼續解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
}
ConfigurationClassUtils.checkConfigurationClassCandidate中的摘取片段
//檢查是否有標識@Configuration
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
//設定配置屬性值為full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//檢查是否包含@Component @ComponentScan @Import @ImportResource @Bean
else if (config != null || isConfigurationCandidate(metadata)) {
//設定配置屬性值為lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
配置類解析流程(parser.parse(candidates))
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
//配置類的beanDefinition為AnnotatedGenericBeanDefinition,true
if (bd instanceof AnnotatedBeanDefinition) {
//傳入配置類的後設資料與beanName
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
}
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
processConfigurationClass
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//解析配置類,這裡可能返回配置類的父類,需要繼續處理
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//將配置類放入map中
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass
//@Configuration 本身也是 @Component的組合註解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 處理內建類,如果內建類也是個配置類,遞迴處理內建類
processMemberClasses(configClass, sourceClass, filter);
}
處理@ComponentScan
// Process any @ComponentScan annotations
// 找出配置類上的@ComponentScan註解屬性
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
for (AnnotationAttributes componentScan : componentScans) {
//將@ComponentScan引入的所有類掃描成BeanDefinition並註冊到容器中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//這裡迴圈是為了判斷掃描出來的beanDefinition是否是配置類,如果是配置類的話需要遞迴解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
//這裡是必然為true, 能被掃描出來的必然有@Component註解,而@Component註解為lite配置類
//這裡主要是為了在檢查的同時設定一下full或者lite的型別
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//配置類就繼續遞迴解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
this.componentScanParser.parse
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//重新new了一個classpath的bean定義掃描器,沒用我們最開始建立的
// 這裡新增了一個預設的過濾器,過濾@Component註解的
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//新增自己配置的過濾器
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//如果配置的為懶載入,則掃描出來的所有BeanDefinition都預設為懶載入的
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
//將配置的basePackages中所有的包路徑放到set集合中,保證最終所有的包路徑唯一
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
//新增一個排除過濾器,排除該配置類
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//開始掃描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//找到所有候選的bean -> 預設過濾器為過濾標識了@Component註解的class
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//設定預設值,比如上一個方法剛剛設定的是否懶載入
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//解析beanClass的所有註解填充到beanDefinition中,@Lazy @Primary @DependsOn @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//檢查之前是否註冊過,未註冊返回true
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
beanDefinitions.add(definitionHolder);
//將beanDefinition註冊到容器中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
尋找候選元件#findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
return scanCandidateComponents(basePackage);
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
//將類路徑替換成絕對路徑
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//找出該路徑下的所有類資源
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//呼叫剛剛配置的過濾器進行匹配,
//預設過濾器邏輯:是否標識了@Component註解(包括組合的,如@Service)
if (isCandidateComponent(metadataReader)) {
//通過掃描方式建立的BeanDefintion為ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//不是介面和抽象類,或者是抽象類但標識了@Lookup
if (isCandidateComponent(sbd)) {
//將beanDefinition存到集合中
candidates.add(sbd);
}
}
}
}
return candidates;
}
處理@Import
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
//importCandidates為@Import中的value陣列
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//例項化我們寫的實現ImportSelector介面的類
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
//呼叫selectImports方法返回我們需要注入到容器中bean陣列
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//轉為SourceClass集合
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//再次遞迴呼叫本方法,如果我們返回的陣列是一些沒有實現Import相關介面的類,
//就會走到最後的else邏輯,當成配置類處理
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
//這裡就走實現ImportBeanDefinitionRegistrar介面的邏輯
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
//例項化
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
//這裡先把Registrar放到配置類的importBeanDefinitionRegistrars屬性中,最後解析完呼叫loadBeanDefinition進行處理
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
//普通的bean當做配置類處理
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
處理@Bean
// 將配置類中@Bean的方法解析成方法後設資料放到配置類中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
到這裡配置類的主要解析流程就已經結束了,接下來回到解析之後的流程
處理@Import匯入的beanDefintion和配置類中的@Bean
this.reader.loadBeanDefinitions(configClasses);
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//迴圈剛剛解析過的所有配置類
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 將Import註解引入的class註冊到容器的BeanDefinitionMap中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//將beanMethod轉化成BeanDefinition註冊到容器的beanDefinitionMap中
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//呼叫在解析Import時放入的ImportBeanDefinitionRegistrar的registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
摘取處理BeanMethod邏輯如下
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
//解析出方法上@Bean註解的所有屬性值
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
//建立一個ConfigurationClassBeanDefinition,標識為通過@Bean註解註冊的bean
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//以下邏輯為拿出@Bean中的屬性填充到BeanDefinition中,最後註冊容器中
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
//解析註解填充屬性
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
//將建立的BeanDefinition註冊到容器中
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
以上,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法大致過程就這些了,接下來回到剛開始的invokeBeanFactoryPostProcessors方法
invokeBeanFactoryPostProcessors
處理實現了Ordered介面的BeanDefinitionRegistryPostProcessor
//...省略之前程式碼片段
//呼叫ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空,以便處理後面的後置處理器
currentRegistryProcessors.clear();
//再次查詢實現了BeanDefinitionRegistryPostProcessor介面的BeanName,這裡就是從配置類中解析出來的一些
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//不包括已經處理過的,並且先處理實現Ordered介面的
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//根據Ordered排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//將後置處理器放到已註冊的集合中
registryProcessors.addAll(currentRegistryProcessors);
//呼叫所有後置處理器的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//再次清理,因為後面還要處理未實現Ordered介面的
currentRegistryProcessors.clear();
最後需要迴圈處理剩下的所有後置處理器,因為可能從剩下的後置處理器中又解析出新的後置處理器
//下面的邏輯和上面的一模一樣,while迴圈處理所有剩下的後置處理器,直到全部處理完畢
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);
currentRegistryProcessors.clear();
}
呼叫所有後置處理器的postProcessBeanFactory方法
/**
* 呼叫所有後置處理器的postProcessBeanFactory方法,
* 如果自己沒實現的話,Spring中只有一個內建的ConfigurationClassPostProcessor
* ConfigurationClassPostProcessor中的postProcessBeanFactory方法主要是將配置類換成動態代理
*/
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
ConfigurationClassPostProcessor#postProcessBeanFactory
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//將所有配置類進行動態代理,這樣@Bean中依賴其他的Bean就可以從容器中拿bean了
/**
* example:
* @Bean
* public Car car(){
* return new Car(wheel());
* }
* @Bean
* public Wheel wheel(){
* return new Wheel();
* }
* 如果配置類不換成動態代理的話,每次從容器中拿car都將new一個wheel
* 注意,這裡只有full型別的配置類才會生成代理類,lite型別的不會,
* 所以lite型別的配置類每次獲取car都會生成一個wheel
*/
enhanceConfigurationClasses(beanFactory);
//新增一個beanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
最後處理實現了BeanFactoryPostProcessor介面的後置處理器
//處理方式與BeanDefinitionRegistryPostProcessor相同
//找出所有實現了BeanDefinitionRegistryPostProcessor的後置處理器
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//先處理實現PriorityOrdered介面的
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//在處理實現Ordered介面的
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//最後處理普通的
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
到這裡,關於
BeanFactoryPostProcessor
呼叫過程就已經完結了
關於BeanDefinition
的小彩蛋
解析配置類的流程我們已經分析完了,那麼在這過程中用了多少種BeanDefinition
呢?他們對應的型別又是什麼呢?這裡附上本文的一個小彩蛋。
AnnotatedGenericBeanDefinition
:在開始傳入的配置類,以及通過@Import註解引入的BeanScannedGenericBeanDefinition
:通過@Component掃描包引入的BeanConfigurationClassBeanDefinition
:通過@Bean註解引入的BeanRootBeanDefinition
:Spring內部使用,如生產Bean時將其他BeanDefinition
轉成RootBeanDefinition
Mybatis 如何整合 Spring的?
此節知識為概要知識,具體內容將放在Mybatis原始碼系列詳細說明
先帶大家理理思路~
我們知道,在Spring中是可以通過掃描的方式掃描出標識了@Component
註解的class註冊到容器中,並且該class不能為一個介面類(忘了請看上面的掃描邏輯),而我們的mapper
通常又是一個介面類,這是預設不允許被註冊的。那麼該如何解決這個問題呢?
思考:既然預設不允許是介面類,那麼我們是否可以自定義一個掃碼器繼承Spring的掃描器,然後重寫其中判斷是否為介面類的邏輯,這樣,我們不就可以使用我們自定義的掃描器去掃描包就可以了嗎?
問題2:假設上面的方法可行,但是我們掃描出來的BeanDefintion
是個介面,介面是不能被例項化的,那在後面我們createBean
中的例項化步驟又該如何解決呢?
思考:我們知道其實我們的mapper
在mybatis
中本來就是個介面,我們建立時是通過sqlSessionTemplate.getMapper()
的方式建立的,這裡其實是生成了一個代理類返回給我們,那我們應該如何將這個代理類給接到Spring的createBean
過程中呢,如何接過去了豈不是就萬事大吉?
小知識:嘿,不知道大家還記不記的我們的bean
裡有一種特殊的bean
稱為FactoryBean
,我們這個FactoryBean
最後從容器中獲取出來時其實是先拿到這個FactoryBean
,然後呼叫它的getObject()
方法返回我們真正需要的bean
思考:知道這個之後,那麼我們是不是可以使用FactoryBean
,然後將掃描出來的介面(mapper)放到FactoryBean
的屬性中,最後從容器中獲取時只要這樣:
public class FactoryBean{
private Class mapper;
public Object getObject(){
sqlSessionTemplate.getMappper(mapper);
}
}
嘿,看看是不是好像搞定啦~
現在問題好像都已經解決了,那剩下的就是怎麼讓Spring在啟動的時候呼叫我們的自定義掃描器呢?我們現在就來看看原始碼吧
@MapperScan
Mybatis
整合Spring
當然是從@MapperScan
註解看起,因為我們通常情況只加這個註解就可以了
@MapperScan簡要內容如下
// 組合註解,組合了@Import註解,再通過@Import註解匯入了MapperScannerRegistrar類
@Import(MapperScannerRegistrar.class)
public @interface MapperScan{
// 包路徑
String[] basePackages() default {}
}
MapperScannerRegistrar
// 實現的是ImportBeanDefinitionRegistrar介面
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware{
}
registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 從後設資料中拿到@MapperScan的資訊
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
// 例項化一個自定義的掃描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// 下面都是些屬性填充,由於一般我們只配一個包路徑,所以下面除了包路徑,其他都是null
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 註冊自定義的過濾器,我們啥也沒配,所以掃描出來的所以介面都通過
scanner.registerFilters();
// 開始掃描
scanner.doScan(StringUtils.toStringArray(basePackages));
}
scanner.registerFilters中的有效片段
// 新增一個直接返回true的過濾器
addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
doScan
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 直接走的就是Spring的掃描邏輯了,但現在過濾器只有一個預設全放行的
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
// 處理掃描出來的BeanDefinition,這裡就是我們思考中搞成`FactoryBean`的邏輯
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
我們思考中重寫的掃描邏輯
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// 放行是介面的類
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
摘取processBeanDefinitions中的程式碼片段
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
// 將原來的介面mapper放到beanDefintion的構造方法引數中,以指定的構造方法例項化
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
// 注意這裡:將原來的beanClass替換成FactoryBean了!
definition.setBeanClass(this.mapperFactoryBean.getClass());
}
}
Mybatis整合Spring的過程大致就是這些了
Spring 原始碼系列
- Spring原始碼分析之 IOC 容器預啟動流程(已完結)
- Spring原始碼分析之BeanFactory體系結構(已完結)
- Spring原始碼分析之BeanFactoryPostProcessor呼叫過程(已完結)
- Spring原始碼分析之Bean的建立過程
- Spring原始碼分析之什麼是迴圈依賴及解決方案
- Spring原始碼分析之AOP從解析到呼叫
- Spring原始碼分析之事務管理(上),事物管理是spring作為容器的一個特點,總結一下他的基本實現與原理吧
- Spring原始碼分析之事務管理(下) ,關於他的底層事物隔離與事物傳播原理,重點分析一下
Spring Mvc 原始碼系列
- SpringMvc體系結構
- SpringMvc原始碼分析之Handler解析過程
- SpringMvc原始碼分析之請求鏈過程
Mybatis 原始碼系列
暫定
追更,可關注我,近期有時間就文章全寫完,分享純粹為了樂趣,也有一種成就感吧,筆者這篇文章先就到這
關注筆者公眾號:奇客時間,獲取網際網路公司面試真題,回覆關鍵字形式:公司-部門-面試輪次,例如 阿里-螞蟻金服-一面,自動回覆面試真題;當前已經收錄如下:
位元組跳動-抖音-面試輪次, 搜狐-搜尋組-面試輪次, OPPO-商城-面試輪次, 58同城-基礎架構部-面試輪次,湖南臺-芒果TV-面試輪次 , 騰訊-乘車碼-面試輪次 , 騰訊-微信支付-面試輪次 , 騰訊-零售新業務-面試輪次 , 騰訊-直播平臺-面試輪次, 快手-廣告業務部-面試輪次 , 貝殼找房-商品組-面試輪次 , 百度-資訊流-面試輪次 , 京東-零售-面試輪次 , 京東-物流-面試輪次 , 京東-電商-面試輪次 , 滴滴-小桔車服-面試輪次 , 滴滴-金融-面試輪次 , 阿里-高德-面試輪次 , 阿里-大文娛-面試輪次 , 阿里-健康-面試輪次 , 阿里-螞蟻金服-面試輪次 , 美團-外賣-面試輪次 , 美團-風控-面試輪次