Spring類掃描器記錄

1.上下文刷新時,SpringContext將調用BeanFactory後置處理器掃描Class

ConfigurationClassPostProcessor // BeanFactory後置處理器
       postProcessBeanFactory   // 上下文刷新時調用該方法
         processConfigBeanDefinitions
           ConfigurationClassParser parse.parse(main.class)   // Parse each @Configuration class

SpringBoot/SpringContext初始化加載過程可參考邏輯圖:
SpringApplication啓動過程
經過搜索「ConfigurationClassPostProcessor」找到對應節點java

2.parse解析方法將解析類聲明的各類註解

ConfigurationClassParser
       parse
         processConfigurationClass  // 遞歸地處理配置類及其超類層次結構
        do {
               sourceClass = doProcessConfigurationClass { // 返回父類Class, 沒有則返回null
                     processMemberClasses // 先遞歸地處理任何(嵌套)類
                     processPropertySource // 處理註解@PropertySource
                      scannedBeanDefinitions = componentScanParser.parse // 處理註解@ComponentScan
                     for(BeanDefinitionHolder holder : scannedBeanDefinitions) {
                         parse(holder) // 遞歸
                     }
                     processImports // 處理註解@Import
                     configClass.addImportedResource // 處理註解@ImportResource
                     configClass.addBeanMethod // 處理@Bean聲明的方法
                     processInterfaces // 處理接口上的默認方法
                     return sourceClass.getSuperClass // 返回父類給sourceClass
               }
        } while(sourceClass != null)

3.處理註解@ComponentScan, 並調用scanner掃描Class

ComponentScanAnnotationParser componentScanParser.parse
       ClassPathBeanDefinitionScanner **scanner.doScan**
doScan調用
this.resourcePatternResolver.getResources(packageSearchPath)來所搜索指定包下所有的class
搜索路徑示例: classpath*:com/simple/boot/**/*.class
而後進行過濾, 組裝成一個個BeanDefinition後註冊到BeanFactory

ClassPathBeanDefinitionScanner 在Dubbo、MyBatis與Spring的集成中有應用到, 能夠參考以下類:

// Dubbo中, 用於掃描DubboService
com.alibaba.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner 

// MyBatis中, 用於掃描Mapper 
org.mybatis.spring.mapper.ClassPathMapperScanner

問題記錄

1.如何經過包名查找類資源的?

PathMatchingResourcePatternResolver#doFindAllClassPathResources
中調用ClassLoader#getResources("包路徑, 如: com/simple/"),ClassLoader爲Launcher$AppClassLoader, 結果示例:spring

result = 
0 = "URL [file:/D:/simple-boot/target/classes/com/simple/]"
1 = "URL [jar:file:/D:/simple-boot/lib/simple-depend-1.0-SNAPSHOT.jar!/com/simple/]"

這樣會查出類路徑下, 全部符合包名前綴的rootDirURL, 而後循環Root路徑掃描子路徑mybatis

2.怎麼查找文件夾裏面的class?

PathMatchingResourcePatternResolver#doFindPathMatchingFileResources
如問題1中, 根路徑URL [file:/D:/simple-boot/target/classes/com/simple/]將匹配到該查詢方法
該方法遞歸目錄進行搜索app

3.怎麼查找jar包裏面的class?

PathMatchingResourcePatternResolver#doFindPathMatchingJarResources
如問題1中, 根路徑URL [jar:file:/D:/simple-boot/lib/simple-depend-1.0-SNAPSHOT.jar!/com/simple/]將匹配到該查詢方法
將jar文件獲取或建立爲java.util.jar.JarFile的實例, 經過Enumeration<JarEntry> entries = jarFile.entries()方法循環全部文件post

其餘一些記錄

PathMatchingResourcePatternResolver#getResources(String locationPattern)
中, 包名轉換成locationPattern的方式:this

String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;

假設basePackage="com.simple", 則將packageSearchPath會拼裝成classpath*:com/simple/**/*.classspa

相關文章
相關標籤/搜索