十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
使用Springboot怎么对路径进行扫描?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
成都创新互联专注于企业全网整合营销推广、网站重做改版、渝北网站定制设计、自适应品牌网站建设、H5技术、商城网站制作、集团公司官网建设、外贸网站制作、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为渝北等各大城市提供网站开发制作服务。我们暂且标注下Springboot启动过程中较为重要的逻辑方法,源码对应的spring-boot-2.2.2.RELEASE版本
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; CollectionexceptionReporters = 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.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) //这个方法会注入5个bean定义: 1. ConfigurationClassPostProcessor.class 2. 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.BeanDefinitionLoader#load(java.lang.Class>) org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register org.springframework.context.annotation.AnnotatedBeanDefinitionReader#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
看完上述内容,你们掌握使用Springboot怎么对路径进行扫描的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!