使用Springboot怎么对路径进行扫描
创始人
2024-12-26 20:41:52
0次

我们暂且标注下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.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的代码里;

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

使用Springboot怎么对路径进行扫描

由于第二步容器中将启动类包装成AnnotatedGenericBeanDefinition并注入了容器,在方法
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set)会被处理执行后续的包扫描

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...