Springboot自动扫描包路径来龙去脉示例详解

网友投稿 630 2023-02-27

Springboot自动扫描包路径来龙去脉示例详解

Springboot自动扫描包路径来龙去脉示例详解

我们暂且标注下Springboot启动过程中较为重要的逻辑方法,源码对应的spring-boot-2.2.2.RELEASE版本

public ConfigurableApplicationContext run(String... args) {

StopWatch stopWatch = new StopWatch();

stopWatch.start();

ConfigurableApplicationContext context = null;

Collection exceptionReporters = new ArrayList<>();

configureHeadlessProperty();

SpringApplicationRunListeners listeners = getRunListeners(args);

listeners.starting();

try {

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

configureIgnoreBeanInfo(environment);

Banner printedBanner = printBanner(environment);

//@A

context = createApplicationContext();

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,

new Class[] { ConfigurableApplicationContext.class }, context);

//@B

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

//@C

refreshContext(context);

afterRefresh(context, applicationArguments);

stopWatch.stop();

if (this.logStartupInfo) {

new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);

}

listeners.started(context);

callRunners(context, applicationArguments);

}

catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, listeners);

throw new IllegalStateException(ex);

}

try {

listeners.running(context);

}

catch (Throwable ex) {

handleRunFailure(context, ex, exceptionReporters, null);

throw new IllegalStateException(ex);

}

return context;

}

第一步:ConfigurationClassPostProcessor注入

org.springframework.context.annotation.ConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor(父类是BeanFactoryPostProcessor),会在容器初始化好并装载完第一阶段的bean定义后调用,我理解的其主要作用是执行一些框架内部方法也让用户自定义再次注入自定义的bean定义;

它的注册是在SpringApplication.run方法调用后,具体调用链是

org.springframework.boot.SpringApplication#run(java.lang.Class>, java.lang.String...)

->org.springframework.boot.SpringApplication#run(java.lang.String...)

->org.springframework.boot.SpringApplication#createApplicationContext

//对应上面@A标注的地方

//后续会初始化一个org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext对象,在构造方法里会执行一系列的逻辑

->org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry)

->org.springframework.context.annotation.AnnotatedBeanDefinitionReader#AnnotatedBeanDefinitionReader(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.core.env.Environment)

->org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)

->org.http://springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

//这个方法会注入5个bean定义:

1. ConfigurationClassPostProcessor.class

hkgqL2. AutowiredAnnotationBeanPostProcessor.class

3. CommonAnnotationBeanPostProcessor.class

4. EventListenerMethodProcessor.class

5. DefaultEventListenerFactory.class

第二步:启动类bean定义注入

被我们标记了@SpringBootApplication的类在运行过程中会被包装成一个bean定义,放入容器中;具体方法调用链

org.springframework.boot.SpringApplication#run(java.lang.String...)

org.springframework.boot.SpringApplication#prepareContext //对应上面代码标注 @B 的地方

org.springframework.boot.SpringApplication#load

org.springframework.boot.BeanDefinitionLoader#load(java.lang.Object)

org.springframework.boot.BeanDefinitionLoahttp://der#load(java.lang.Class>)

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register

org.springframework.context.annotation.AnnotatedBeanDefinihttp://tionReader#registerBean(java.lang.Class>)

org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean

//里面一段代码 如下:

AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

//从这个方法里可以看出,启动类被包装成了 AnnotatedGenericBeanDefinition(实现了AnnotatedBeanDefinition接口,这很重要)

第三步:解析包扫描信息并完成剩余bean注册

刚刚在第一步里,容器中注入了ConfigurationClassPostProcessor后置处理器,后置处理器会在核心方法refresh中执行,也就是上面标注@C的代码里;

我们直接来到核心逻辑处,调用链:

由于第二步容器中将启动类包装成AnnotatedGenericBeanDefinition并注入了容器,在方法

org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set)会被处理执行后续的包扫描

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:APP启动小程序(打开应用小程序)
下一篇:Springboot+Bootstrap实现增删改查实战
相关文章

 发表评论

暂时没有评论,来抢沙发吧~