springboot默認(rèn)掃描的路徑方式
springboot默認(rèn)掃描的路徑
一般來(lái)說(shuō)spring boot默認(rèn)的掃描路徑是啟動(dòng)類當(dāng)前的包和子包
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(basePackages = {"com.frame.springboot.dao", "com.frame.springboot.base"})
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(SpringbootApplication.class);
app.addListeners(new MyApplicationStartedEventListener());
app.run(args);
}
static class MyApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {
private Logger logger = LoggerFactory.getLogger(MyApplicationStartedEventListener.class);
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
SpringApplication app = event.getSpringApplication();
app.setBannerMode(Banner.Mode.OFF);// 不顯示banner信息
logger.info("==MyApplicationStartedEventListener==");
}
}
}例如這個(gè)類的包和子類
接下來(lái)就從源碼角度來(lái)分析這是為什么
首先這個(gè)加載過程肯定是從refreshcontext中的操作,因此進(jìn)入。
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}這個(gè)操作實(shí)在初始化factorypostprocessors中進(jìn)行的。
接下來(lái)進(jìn)入方法
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}在這里很明顯是把任務(wù)委托給了PostProcessorRegistrationDelegate。
接下來(lái)我們繼續(xù)點(diǎn)擊進(jìn)入
invokeBeanFactoryPostProcessors的方法很長(zhǎng)我只截取我們關(guān)心的代碼
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet();
int var9;
ArrayList currentRegistryProcessors;
String[] postProcessorNames;
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList();
Iterator var6 = beanFactoryPostProcessors.iterator();
while(var6.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
}這里先來(lái)簡(jiǎn)單的說(shuō)一下,首先會(huì)調(diào)用傳入的beanFactoryPostProcessors的postProcessBeanDefinitionRegistry。
處理一般會(huì)調(diào)用
ConfigurationClassPostProcessor類,接下來(lái)進(jìn)去看一下postProcessBeanDefinitionRegistry方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
} else if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
} else {
this.registriesPostProcessed.add(registryId);
this.processConfigBeanDefinitions(registry);
}
}在這里最重要的還是processConfigBeanDefinitions方法,但是這個(gè)方法實(shí)在是太長(zhǎng)了截取重要的步驟
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//省略
parser.parse(candidates);
}這個(gè)方法主要是用來(lái)解析beandefinitions。
進(jìn)入看一下
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList();
Iterator var2 = configCandidates.iterator();
while(var2.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
} else {
this.parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException var6) {
throw var6;
} catch (Throwable var7) {
throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
}
}
this.processDeferredImportSelectors();
}這由于我們使用的是注解來(lái)進(jìn)行那么進(jìn)入第一個(gè)parse,主要調(diào)用了processConfigurationClass 的方法
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
this.configurationClasses.remove(configClass);
Iterator it = this.knownSuperclasses.values().iterator();
while(it.hasNext()) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass);
do {
sourceClass = this.doProcessConfigurationClass(configClass, sourceClass);
} while(sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
}這個(gè)方法獲取config的class和解析,其中主要方法是doProcessConfigurationClass
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass) throws IOException {
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
Iterator var13 = componentScans.iterator();
while(var13.hasNext()) {
AnnotationAttributes componentScan = (AnnotationAttributes)var13.next();
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
Iterator var7 = scannedBeanDefinitions.iterator();
while(var7.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var7.next();
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
}
}只截取了其中的重要部分,看到componentScanParser.parse了,那么基本就想到是要去獲取Component組件了,為什么config會(huì)和component關(guān)系呢,請(qǐng)看一下注解內(nèi)部里面有一個(gè)@component。
接下來(lái)進(jìn)去看一下
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
Set<String> basePackages = new LinkedHashSet();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
String[] var19 = basePackagesArray;
int var21 = basePackagesArray.length;
int var22;
for(var22 = 0; var22 < var21; ++var22) {
String pkg = var19[var22];
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ",; \t\n");
basePackages.addAll(Arrays.asList(tokenized));
}
Class[] var20 = componentScan.getClassArray("basePackageClasses");
var21 = var20.length;
for(var22 = 0; var22 < var21; ++var22) {
Class<?> clazz = var20[var22];
basePackages.add(ClassUtils.getPackageName(clazz));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
}這個(gè)代碼是為了尋找可以掃描的基礎(chǔ)包,但是在創(chuàng)建啟動(dòng)類的時(shí)候我們并沒有設(shè)置也就是basePackages.isEmpty()==true。
接下來(lái)的操作是添加declaringClass路徑,那么這個(gè)類是什么呢。
這個(gè)類就是你的啟動(dòng)類。
所以真正設(shè)置掃描路徑的代碼在這。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
JUC并發(fā)編程LinkedBlockingQueue隊(duì)列深入分析源碼
LinkedBlockingQueue 是一個(gè)可選有界阻塞隊(duì)列,這篇文章主要為大家詳細(xì)介紹了Java中LinkedBlockingQueue的實(shí)現(xiàn)原理與適用場(chǎng)景,感興趣的可以了解一下2023-04-04
dockerfile-maven-plugin極簡(jiǎn)教程(推薦)
這篇文章主要介紹了dockerfile-maven-plugin極簡(jiǎn)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
PL/SQL實(shí)現(xiàn)JAVA中的split()方法的例子
這篇文章主要介紹了PL/SQL實(shí)現(xiàn)JAVA中的split()方法的例子的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Spring Cloud中各組件超時(shí)總結(jié)
在大家學(xué)習(xí)spring cloud的時(shí)候組件是必不可少的一部分,下面這篇文章主要給大家介紹了關(guān)于Spring Cloud中各組件超時(shí)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-11-11
springBoot項(xiàng)目啟動(dòng)類啟動(dòng)無(wú)法訪問的解決方法
這篇文章主要介紹了springBoot項(xiàng)目啟動(dòng)類啟動(dòng)無(wú)法訪問的解決方法,需要的朋友可以參考下2018-10-10
springboot 實(shí)現(xiàn)記錄業(yè)務(wù)日志和異常業(yè)務(wù)日志的操作
這篇文章主要介紹了springboot 實(shí)現(xiàn)記錄業(yè)務(wù)日志和異常業(yè)務(wù)日志的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

