Springboot启动原理和自动配置原理

这篇具有很好参考价值的文章主要介绍了Springboot启动原理和自动配置原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关于 springboot 启动流程和配置原理 很久就写了,不过没有详细补充 ,现在补充 —— 2023-08-05

启动原理

@SpringBootApplication
public class Start {

    public static void main(String[] args) {
        SpringApplication.run(Start.class, args);
    }

}

SpringApplication

 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet(); // 
        this.bannerMode = Mode.CONSOLE;// 控制banner
        this.logStartupInfo = true;// 是否启动日志
        this.addCommandLineProperties = true; // 读取命令行配置
        this.addConversionService = true; //添加转换器
        this.headless = true; // 
        this.registerShutdownHook = true; // 注册重启
        this.additionalProfiles = Collections.emptySet();// 读取配置环境
        this.isCustomEnvironment = false;// 是否是自定义环境
        this.lazyInitialization = false; // 是否懒加载
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT; // ApplicationStartup DEFAULT = new DefaultApplicationStartup();
        this.resourceLoader = resourceLoader;// 资源加载器
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); // 主程序
        this.webApplicationType = WebApplicationType.deduceFromClasspath();//  SERVLET||REACTIVE; 是servlet还是reactive环境
        // BootstrapRegistryInitializer
	this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        // ApplicationContextInitializer
	this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// ApplicationListener        
	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

BootstrapRegistryInitializer

BootstrapRegistryInitializer 是一个函数是接口

@FunctionalInterface
public interface BootstrapRegistryInitializer {
	void initialize(BootstrapRegistry registry);
}

org.springframework.boot.BootstrapRegistry 接口

getSpringFactoriesInstances

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// 使用 set 结构去重
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        
        // 加载完毕后排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

加载工厂中组件实现方式

org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories

// 1、加载配置
 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();
            try {
                 //核心 从这里知道读取配置文件位置 默认
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");
		        // ... 这里省略迭代器遍历注册
                
                // result.replaceAll  该函数的作用是对每个值进行去重,并将去重后的结果存储为一个不可修改的列表。最后,replaceAll 方法使用这个函数的结果来替换原始的键值对中的值
                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
		        // 添加到缓存中 下次读取先获取类加载器 通过类加载器获取 map 结构再获取 bean
                // cache 结构
                // 	static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap<>();
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                // 错误异常信息
            }
        }
    }

加载的配置文件

spring-boot:2.7.1.META-INF\spring.factorie

org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

像 BootstrapRegistryInitializer

另外几个配置是从其他配置文件中读取的

例如

createSpringFactoriesInstances

``org.springframework.core.io.support.SpringFactoriesLoader#createSpringFactoriesInstances 构建实例对象



// 2、获取构造器实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList(names.size());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                // 通过类名反射机制调用,读取Class<T> class
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                // 通过 BeanUtils 提供静态方法 instantiateClass () 
                // 通过构造函数 和参数 构造一个实例对象
                // 最终调用的是 
 		T instance = BeanUtils.instantiateClass(constructor, args);
                // 添加到构造器中
                instances.add(instance);
            } catch (Throwable var12) {
                // throw error
            }
        }
	// 返回
        return instances;
    }


// 排序 通过debug这里调用的是Integer类型排序方法 List<Integer> list
  public static void sort(List<?> list) {
        if (list.size() > 1) {
            list.sort(INSTANCE);
        }

    }

需要注意的是 BeanUtils.instantiateClass 最终调用的是java.lang.Class#form0 由 底层实现

    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)
        throws ClassNotFoundException;

AnnotationAwareOrderComparator

加载实例完毕后是由 org.springframework.core.annotation.AnnotationAwareOrderComparator


public class AnnotationAwareOrderComparator extends OrderComparator {

	public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
	public static void sort(List<?> list) {
		if (list.size() > 1) {
            // 采用单例模式实现
            // 比较器由 OrderComparator 实现
			list.sort(INSTANCE);
		}
	}
}

比较器实现 org.springframework.core.OrderComparator#doCompare()

	private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
        // PriorityOrdered 是一种优先级排序
		boolean p1 = (o1 instanceof PriorityOrdered);
		boolean p2 = (o2 instanceof PriorityOrdered);
        
        
        // 逆序
		if (p1 && !p2) {
			return -1;
		}
        // 顺序
		else if (p2 && !p1) {
			return 1;
		}
		int i1 = getOrder(o1, sourceProvider);
		int i2 = getOrder(o2, sourceProvider);
        
        // 最终交给 Integer 的比较器排序
		return Integer.compare(i1, i2);
	}

ApplicationContextInitializer

BootstrapRegistryInitializer加载原理

ApplicationListener

BootstrapRegistryInitializer加载原理

总结

run

执行流程

public ConfigurableApplicationContext run(String... args) {
        // 初次启动时间
        long startTime = System.nanoTime();
        // 默认上下文环境
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 加载配置文件
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            
            // 图形 Banner
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            // 加载所有注解使用的扫描的组件
	        this.refreshContext(context);
	        // 刷新
            this.afterRefresh(context, applicationArguments);
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
            }

            // 启动 listener
            listeners.started(context, timeTakenToStartup);
            
            // 加载完毕处理 调用函数是接口 ApplicationRunner run 方法
            // ApplicationRunner
            // CommandLineRunner
            this.callRunners(context, applicationArguments);
        } catch (Throwable var12) {
            // 启动失败调用 ApplicationEventPublisher 接口实现
            // 事件推送
            this.handleRunFailure(context, var12, listeners);
            throw new IllegalStateException(var12);
        }

        try {
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            // 加载完毕 事件通过 doWithListeners 触发
            listeners.ready(context, timeTakenToReady);
            return context;
        } catch (Throwable var11) {
            this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var11);
        }
    }

createBootstrapContext

	private DefaultBootstrapContext createBootstrapContext() {
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
		return bootstrapContext;
	}

configureHeadlessProperty

	private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

getRunListeners


	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
                   // 获取 SpringApplicationRunListener 类型 侦听器, 在构造函数创建时候已经调用了
                   // 
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

获取 侦听器,这次走缓存

listeners.starting

启动侦听器经过这里 org.springframework.boot.SpringApplicationRunListeners

	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}

	@Override
	public void starting(ConfigurableBootstrapContext bootstrapContext) {
		this.initialMulticaster
				.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
	}

最终触发事件 org.springframework.context.event.SimpleApplicationEventMulticaster

	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			// 异常处理
		}
	}

org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationEvent

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationStartingEvent) {
			onApplicationStartingEvent((ApplicationStartingEvent) event);
		}
		else if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		else if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent((ApplicationPreparedEvent) event);
		}
		else if (event instanceof ContextClosedEvent) {
			onContextClosedEvent((ContextClosedEvent) event);
		}
		else if (event instanceof ApplicationFailedEvent) {
			onApplicationFailedEvent();
		}
	}

DefaultApplicationArguments

默认参数类 org.springframework.boot.DefaultApplicationArguments

此构造函数作用是保存命令参数 如 java -jar -Dspring.xxxx.yyy=cccc mmm.jar 获取参数信息

	public DefaultApplicationArguments(String... args) {
		Assert.notNull(args, "Args must not be null");
		this.source = new Source(args);
		this.args = args;
	}

prepareEnvironment

配置文件加载在这个逻辑中

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		// 获取配置环境 默认是 servlet
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 环境参数处理
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
        // 启动配置文件的侦听器
        // 读取配置文件
		listeners.environmentPrepared(bootstrapContext, environment);
        // 默认配置文件合并
		DefaultPropertiesPropertySource.moveToEnd(environment);
		Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
				"Environment prefix cannot be set via properties.");
        // 配置内容绑定到 SpringApplication 这个类中
		bindToSpringApplication(environment);
        // 非自定义环境
		if (!this.isCustomEnvironment) {
			environment = convertEnvironment(environment);
		}
        // 所有配置内容合并
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

获取 web 环境

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
        
        // 如果不做默认配置 默认是 SERVLET
		switch (this.webApplicationType) {
            // 默认 servelt 环境
			case SERVLET:
				return new ApplicationServletEnvironment();
            // 响应式编程
			case REACTIVE:
				return new ApplicationReactiveWebEnvironment();
			default:
				return new ApplicationEnvironment();
		}
	}

配置文件加载流程

	void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
		doWithListeners("spring.boot.application.environment-prepared",
				(listener) -> listener.environmentPrepared(bootstrapContext, environment));
	}

org.springframework.boot.env.EnvironmentPostProcessorApplicationListener#onApplicationEnvironmentPreparedEvent()

	private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
		ConfigurableEnvironment environment = event.getEnvironment();
		SpringApplication application = event.getSpringApplication();
		for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
				event.getBootstrapContext())) {
			postProcessor.postProcessEnvironment(environment, application);
		}
	}

org.springframework.core.env.#addFirst

	public void addFirst(PropertySource<?> propertySource) {
		synchronized (this.propertySourceList) {
			removeIfPresent(propertySource);
            // 添加第一个位置
			this.propertySourceList.add(0, propertySource);
		}
	}

第一个配置类包括所有内容

configureIgnoreBeanInfo

	private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

printBanner

	private Banner printBanner(ConfigurableEnvironment environment) {
        // 如果 Banner.Mode.OFF 将不会打印Banner内容
        // 默认为 CONOSLE 也就是输出
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(null);
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

org.springframework.boot.SpringApplicationBannerPrinter#print

阅读上面内容知道一下内容

  • 指定位置信息
  • 指定图片位置信息
  • 默认为 banner.txt
  • 图片格式
	

Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
		Banner banner = getBanner(environment);
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}

org.springframework.boot.SpringBootBanner

默认Banner 内容

class SpringBootBanner implements Banner {

	private static final String[] BANNER = { "", "  .   ____          _            __ _ _",
			" /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
			" \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /",
			" =========|_|==============|___/=/_/_/_/" };

	private static final String SPRING_BOOT = " :: Spring Boot :: ";

	private static final int STRAP_LINE_SIZE = 42;

	@Override
	public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
		for (String line : BANNER) {
            // 输出 BANNER
			printStream.println(line);
		}
          // 获取版本号信息
		String version = SpringBootVersion.getVersion();
     
		version = (version != null) ? " (v" + version + ")" : "";
		StringBuilder padding = new StringBuilder();
		while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
			padding.append(" ");
		}

        // 最终经过 打印流输出 上面内容
		printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
				AnsiStyle.FAINT, version));
		printStream.println();
	}

}

createApplicationContext

org.springframework.boot.ApplicationContextFactory

获取服务器环境 默认是 servlet环境

	ApplicationContextFactory DEFAULT = (webApplicationType) -> {
		try {
			for (ApplicationContextFactory candidate : SpringFactoriesLoader
					.loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
				ConfigurableApplicationContext context = candidate.create(webApplicationType);
				if (context != null) {
					return context;
				}
			}
			return new AnnotationConfigApplicationContext();
		}
		catch (Exception ex) {
		   // hanlder error
		}
	};

重写接口两个类

setApplicationStartup

设置

prepareContext

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        // 上下文中设置环境
        context.setEnvironment(environment);
        // 上下文处理
        postProcessApplicationContext(context);
        // 初始化
        applyInitializers(context);
        // 监听器中放入上下文
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 单例对象注册
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        // 加载上下文
        load(context, sources.toArray(new Object[0]));
        // 监听器做加载上下文操作
        listeners.contextLoaded(context);
    }

注册类型转换器

refreshContext

核心实现 org.springframework.context.support.AbstractApplicationContext.refresh()

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

afterRefresh

这个方法什么都没写 为以后拓展需要

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

started

任务开始启动中...

	void started(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
	}

org.springframework.boot.context.event.EventPublishingRunListener#started()实现

	@Override
	public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        // 发布事件
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
        // 发布事件
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}

实现类

callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
        // 从容器工厂中获取 ApplicationRunner 和  CommandLineRunner 的子类对象
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        // 排序下
		AnnotationAwareOrderComparator.sort(runners);
        // 执行 run
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
// // org.springframework.boot.CommandLineRunner
@FunctionalInterface
public interface ApplicationRunner {
	void run(ApplicationArguments args) throws Exception;
}


// org.springframework.boot.CommandLineRunner

@FunctionalInterface
public interface CommandLineRunner {
	void run(String... args) throws Exception;
}

org.springframework.boot.SpringApplication.callRunner


	private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
            // 调用接口
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}
	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
             // 调用接口
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}

handleRunFailure

	private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
			SpringApplicationRunListeners listeners) {
		try {
			try {
				handleExitCode(context, exception);
				if (listeners != null) {
					listeners.failed(context, exception);
				}
			}
			finally {
				reportFailure(getExceptionReporters(context), exception);
				if (context != null) {
					context.close();
					shutdownHook.deregisterFailedApplicationContext(context);
				}
			}
		}
		catch (Exception ex) {
			logger.warn("Unable to close ApplicationContext", ex);
		}
		ReflectionUtils.rethrowRuntimeException(exception);
	}

private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) {
        // 获取错误 code
		int exitCode = getExitCodeFromException(context, exception);
        // 为什么是 不等于 0 ? 
        // 因为系统认为 System.exit(0) 是强制退出
		if (exitCode != 0) {
			if (context != null) {
                // 发布错误 event
				context.publishEvent(new ExitCodeEvent(context, exitCode));
			}
			SpringBootExceptionHandler handler = getSpringBootExceptionHandler();
			if (handler != null) {
                // 注册错误 code
				handler.registerExitCode(exitCode);
			}
		}
	}

ready

执行到这里基本上就完毕了,ready 意为就绪

	void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
	}

doWithListeners

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
        
        // 触发 监听器 事件
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
            // 触发事件
			stepAction.accept(step);
		}
        // 结束
		step.end();
	}

所有组件经过org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader方法加载注册组件

org.springframework.beans.factory.support.DefaultListableBeanFactory

  • registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition())

自动配置原理

思考问题

了解自动配置之前你可以思考以下问题

  • 组件是如何注册的呢?如果让你来实现你扫描组件你会如何实现?需要注意哪些需求?
  • 批量注册

使用中只需要在主类中使用 @SpringBootApplication 注解就可以扫描该类包下 所有注册的组件,注册组件

SpringBootApplication

// ... 常见省略
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    @AliasFor(annotation = ComponentScan.class,attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = ComponentScan.class,attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(annotation = ComponentScan.class,attribute = "nameGenerator")
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    @AliasFor(annotation = Configuration.class)
    boolean proxyBeanMethods() default true;
}

核心注解是

  • @SpringBootConfiguration

    • 本质是一个配置类
  • @EnableAutoConfiguration

    • 自动配置核心

EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

核心是@Import({AutoConfigurationImportSelector.class}) ,将 AutoConfigurationImportSelector 注入实现了自动配置,也就是说 AutoConfigurationImportSelector 类具有自动注入组件功能,下面看看

AutoConfigurationImportSelector 类的实现吧

AutoConfigurationImportSelector

processConfigBeanDefinitions

解析配置文件类

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()

核心实现部分

	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        // 获取所有已注册的 bean 的 name
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
            // 通过 name 从 工厂中获取 bean
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            // 	public static final String CONFIGURATION_CLASS_ATTRIBUTE =
			//Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				// ...
			}
            // 是不是配置类
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

		// 根据条件排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

        // 运行环境判断
        // 没有赋值一个默认环境
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 解析所有配置类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
        // 去重
		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        // 开始遍历所有配置类
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
            // 核心逻辑
			parser.parse(candidates);
            // 校验
			parser.validate();

           // 获取所有配置类
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            // 释放缓存
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
            // reader 读取
            // org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
       // ...
	}

parse

org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGrouping#getImports

	public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
                // 开始执行解析
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
		}

可以看到类型是org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector$AutoConfigurationGroup#parse()

		@Override
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
             // ...
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
                    // 读取配置信息
                    
					.getAutoConfigurationEntry(annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry

判断是否开启了自动配置类注解

	protected boolean isEnabled(AnnotationMetadata metadata) {
		if (getClass() == AutoConfigurationImportSelector.class) {
			return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
		}
		return true;
	}

读取的自动配置类

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 加载 工厂中所有自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 去重
		configurations = removeDuplicates(configurations);
        // 获取排除的类型
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        // 排除 需要排除的类型
		checkExcludedClasses(configurations, exclusions);
        // 清空 释放内存
		configurations.removeAll(exclusions);
        // 获取过滤信息
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

​ 经过筛选之后可以看到

``org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations`

`

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        // 获取 EnableAutoConfiguration.class bean
        // 这就是为什么自动配置必须要使用 @EnableAutoConfiguration 这个注解了
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		// 断言部分 ...
		return configurations;
	}


org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations

// 这就是为什么自动配置必须要使用 @EnableAutoConfiguration 这个注解了
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
	return EnableAutoConfiguration.class;
}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#fireAutoConfigurationImportEvents

	private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
        // 获取自动配置类的监听器
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
            // 获取 event
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#invokeAwareMethods

调用不同类型 event

	private void invokeAwareMethods(Object instance) {
		if (instance instanceof Aware) {
			if (instance instanceof BeanClassLoaderAware) {
				((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);
			}
			if (instance instanceof BeanFactoryAware) {
				((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);
			}
			if (instance instanceof EnvironmentAware) {
				((EnvironmentAware) instance).setEnvironment(this.environment);
			}
			if (instance instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);
			}
		}
	}

selectImports

	@Override
		public Iterable<Entry> selectImports() {
            // 非空
			if (this.autoConfigurationEntries.isEmpty()) {
				return Collections.emptyList();
			}
           // 一下所有都是根据条件注解过滤
			Set<String> allExclusions = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            //
			Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
					.collect(Collectors.toCollection(LinkedHashSet::new));
			processedConfigurations.removeAll(allExclusions);

            // 排序
			return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
					.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
					.collect(Collectors.toList());
		}

validate

校验核心逻辑

	void validate(ProblemReporter problemReporter) {
		// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
		Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
        // 获取 proxyBeanMethods 属性
		if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
            // proxyBeanMethods 为 true 才执行下面逻辑
			if (this.metadata.isFinal()) {
				problemReporter.error(new FinalConfigurationProblem());
			}
			for (BeanMethod beanMethod : this.beanMethods) {
                // 校验 有 BeanMethod类实现
				beanMethod.validate(problemReporter);
			}
		}
	}

org.springframework.context.annotation.BeanMethod#validate

	@Override
	public void validate(ProblemReporter problemReporter) {
        // 对于静态的方法直接返回
		if (getMetadata().isStatic()) {
		
			return;
		}

        // 包含有配置类注解 Configuration.class
		if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) 
            {
            // 重写
			if (!getMetadata().isOverridable()) {
				problemReporter.error(new NonOverridableMethodError());
			}
		}
	}

readaer

	public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader

这个类负责处理 配置的各种属性

  • 别名
  • ref
  • autowire

核心方法是``org.springframework.context.annotation.ConfigurationClassBeanDefinitionReaderloadBeanDefinitionsForBeanMethod`

随便贴点吧

	private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		MethodMetadata metadata = beanMethod.getMetadata();
		String methodName = metadata.getMethodName();

		// Do we need to mark the bean as skipped by its condition?
		if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
			configClass.skippedBeanMethods.add(methodName);
			return;
		}
		if (configClass.skippedBeanMethods.contains(methodName)) {
			return;
		}

		AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
		Assert.state(bean != null, "No @Bean annotation attributes");

		// Consider name and any aliases
		List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

		
        // 别名组件
		for (String alias : names) {
			this.registry.registerAlias(beanName, alias);
		}

		// Has this effectively been overridden before (e.g. via XML)?
		if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
			if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
				// ...
			}
			return;
		}

		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

		if (metadata.isStatic()) {
			// static @Bean method
			if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
				beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
			}
			else {
				beanDef.setBeanClassName(configClass.getMetadata().getClassName());
			}
			beanDef.setUniqueFactoryMethodName(methodName);
		}
		else {
			// instance @Bean method
			beanDef.setFactoryBeanName(configClass.getBeanName());
			beanDef.setUniqueFactoryMethodName(methodName);
		}

		if (metadata instanceof StandardMethodMetadata) {
			beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
		}

		beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
				SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

		AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

		Autowire autowire = bean.getEnum("autowire");
		if (autowire.isAutowire()) {
			beanDef.setAutowireMode(autowire.value());
		}

		boolean autowireCandidate = bean.getBoolean("autowireCandidate");
		if (!autowireCandidate) {
			beanDef.setAutowireCandidate(false);
		}

		String initMethodName = bean.getString("initMethod");
		if (StringUtils.hasText(initMethodName)) {
			beanDef.setInitMethodName(initMethodName);
		}

		String destroyMethodName = bean.getString("destroyMethod");
		beanDef.setDestroyMethodName(destroyMethodName);

		// Consider scoping
		ScopedProxyMode proxyMode = ScopedProxyMode.NO;
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
		if (attributes != null) {
			beanDef.setScope(attributes.getString("value"));
			proxyMode = attributes.getEnum("proxyMode");
			if (proxyMode == ScopedProxyMode.DEFAULT) {
				proxyMode = ScopedProxyMode.NO;
			}
		}

		// ref
		BeanDefinition beanDefToRegister = beanDef;
		if (proxyMode != ScopedProxyMode.NO) {
			BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
					new BeanDefinitionHolder(beanDef, beanName), this.registry,
					proxyMode == ScopedProxyMode.TARGET_CLASS);
			beanDefToRegister = new ConfigurationClassBeanDefinition(
					(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata, beanName);
		}

		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
	}

AutoConfigurationImportSelector 补充

标志位信息

标志位数字,JMV加载后的标志位 由 org.springframework.asm.Opcodes,由于存放在接口中的常量,天然是静态方法文章来源地址https://www.toymoban.com/news/detail-424489.html

public interface Opcodes {

  // ASM API versions.

  int ASM4 = 4 << 16 | 0 << 8;
  int ASM5 = 5 << 16 | 0 << 8;
  int ASM6 = 6 << 16 | 0 << 8;
  int ASM7 = 7 << 16 | 0 << 8;
  int ASM8 = 8 << 16 | 0 << 8;
  int ASM9 = 9 << 16 | 0 << 8;

  int SOURCE_DEPRECATED = 0x100;
  int SOURCE_MASK = SOURCE_DEPRECATED;
  int V1_1 = 3 << 16 | 45;
  int V1_2 = 0 << 16 | 46;
  int V1_3 = 0 << 16 | 47;
  int V1_4 = 0 << 16 | 48;
  int V1_5 = 0 << 16 | 49;
  int V1_6 = 0 << 16 | 50;
  int V1_7 = 0 << 16 | 51;
  int V1_8 = 0 << 16 | 52;
  int V9 = 0 << 16 | 53;
  int V10 = 0 << 16 | 54;
  int V11 = 0 << 16 | 55;
  int V12 = 0 << 16 | 56;
  int V13 = 0 << 16 | 57;
  int V14 = 0 << 16 | 58;
  int V15 = 0 << 16 | 59;
  int V16 = 0 << 16 | 60;
  int V17 = 0 << 16 | 61;
  int V18 = 0 << 16 | 62;
  int V19 = 0 << 16 | 63;

  /**
   * Version flag indicating that the class is using 'preview' features.
   *
   * <p>{@code version & V_PREVIEW == V_PREVIEW} tests if a version is flagged with {@code
   * V_PREVIEW}.
   */
  int V_PREVIEW = 0xFFFF0000;

  // Access flags values, defined in
  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1
  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1
  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1
  // - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25

  int ACC_PUBLIC = 0x0001; // class, field, method
  int ACC_PRIVATE = 0x0002; // class, field, method
  int ACC_PROTECTED = 0x0004; // class, field, method
  int ACC_STATIC = 0x0008; // field, method
  int ACC_FINAL = 0x0010; // class, field, method, parameter
  int ACC_SUPER = 0x0020; // class
  int ACC_SYNCHRONIZED = 0x0020; // method
  int ACC_OPEN = 0x0020; // module
  int ACC_TRANSITIVE = 0x0020; // module requires
  int ACC_VOLATILE = 0x0040; // field
  int ACC_BRIDGE = 0x0040; // method
  int ACC_STATIC_PHASE = 0x0040; // module requires
  int ACC_VARARGS = 0x0080; // method
  int ACC_TRANSIENT = 0x0080; // field
  int ACC_NATIVE = 0x0100; // method
  int ACC_INTERFACE = 0x0200; // class
  int ACC_ABSTRACT = 0x0400; // class, method
  int ACC_STRICT = 0x0800; // method
  int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
  int ACC_ANNOTATION = 0x2000; // class
  int ACC_ENUM = 0x4000; // class(?) field inner
  int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
  int ACC_MODULE = 0x8000; // class

  // ASM specific access flags.
  // WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
  // access flags, and also to make sure that these flags are automatically filtered out when
  // written in class files (because access flags are stored using 16 bits only).

  int ACC_RECORD = 0x10000; // class
  int ACC_DEPRECATED = 0x20000; // class, field, method

  // Possible values for the type operand of the NEWARRAY instruction.
  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray.

  int T_BOOLEAN = 4;
  int T_CHAR = 5;
  int T_FLOAT = 6;
  int T_DOUBLE = 7;
  int T_BYTE = 8;
  int T_SHORT = 9;
  int T_INT = 10;
  int T_LONG = 11;

  // Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures.
  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8.

  int H_GETFIELD = 1;
  int H_GETSTATIC = 2;
  int H_PUTFIELD = 3;
  int H_PUTSTATIC = 4;
  int H_INVOKEVIRTUAL = 5;
  int H_INVOKESTATIC = 6;
  int H_INVOKESPECIAL = 7;
  int H_NEWINVOKESPECIAL = 8;
  int H_INVOKEINTERFACE = 9;

  // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.

  /** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
  int F_NEW = -1;

  /** A compressed frame with complete frame data. */
  int F_FULL = 0;

  /**
   * A compressed frame where locals are the same as the locals in the previous frame, except that
   * additional 1-3 locals are defined, and with an empty stack.
   */
  int F_APPEND = 1;

  /**
   * A compressed frame where locals are the same as the locals in the previous frame, except that
   * the last 1-3 locals are absent and with an empty stack.
   */
  int F_CHOP = 2;

  /**
   * A compressed frame with exactly the same locals as the previous frame and with an empty stack.
   */
  int F_SAME = 3;

  /**
   * A compressed frame with exactly the same locals as the previous frame and with a single value
   * on the stack.
   */
  int F_SAME1 = 4;

  // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}.

  Integer TOP = Frame.ITEM_TOP;
  Integer INTEGER = Frame.ITEM_INTEGER;
  Integer FLOAT = Frame.ITEM_FLOAT;
  Integer DOUBLE = Frame.ITEM_DOUBLE;
  Integer LONG = Frame.ITEM_LONG;
  Integer NULL = Frame.ITEM_NULL;
  Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS;

  // The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and
  // where '-' means 'same method name as on the previous line').
  // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.

  int NOP = 0; // visitInsn
  int ACONST_NULL = 1; // -
  int ICONST_M1 = 2; // -
  int ICONST_0 = 3; // -
  int ICONST_1 = 4; // -
  int ICONST_2 = 5; // -
  int ICONST_3 = 6; // -
  int ICONST_4 = 7; // -
  int ICONST_5 = 8; // -
  int LCONST_0 = 9; // -
  int LCONST_1 = 10; // -
  int FCONST_0 = 11; // -
  int FCONST_1 = 12; // -
  int FCONST_2 = 13; // -
  int DCONST_0 = 14; // -
  int DCONST_1 = 15; // -
  int BIPUSH = 16; // visitIntInsn
  int SIPUSH = 17; // -
  int LDC = 18; // visitLdcInsn
  int ILOAD = 21; // visitVarInsn
  int LLOAD = 22; // -
  int FLOAD = 23; // -
  int DLOAD = 24; // -
  int ALOAD = 25; // -
  int IALOAD = 46; // visitInsn
  int LALOAD = 47; // -
  int FALOAD = 48; // -
  int DALOAD = 49; // -
  int AALOAD = 50; // -
  int BALOAD = 51; // -
  int CALOAD = 52; // -
  int SALOAD = 53; // -
  int ISTORE = 54; // visitVarInsn
  int LSTORE = 55; // -
  int FSTORE = 56; // -
  int DSTORE = 57; // -
  int ASTORE = 58; // -
  int IASTORE = 79; // visitInsn
  int LASTORE = 80; // -
  int FASTORE = 81; // -
  int DASTORE = 82; // -
  int AASTORE = 83; // -
  int BASTORE = 84; // -
  int CASTORE = 85; // -
  int SASTORE = 86; // -
  int POP = 87; // -
  int POP2 = 88; // -
  int DUP = 89; // -
  int DUP_X1 = 90; // -
  int DUP_X2 = 91; // -
  int DUP2 = 92; // -
  int DUP2_X1 = 93; // -
  int DUP2_X2 = 94; // -
  int SWAP = 95; // -
  int IADD = 96; // -
  int LADD = 97; // -
  int FADD = 98; // -
  int DADD = 99; // -
  int ISUB = 100; // -
  int LSUB = 101; // -
  int FSUB = 102; // -
  int DSUB = 103; // -
  int IMUL = 104; // -
  int LMUL = 105; // -
  int FMUL = 106; // -
  int DMUL = 107; // -
  int IDIV = 108; // -
  int LDIV = 109; // -
  int FDIV = 110; // -
  int DDIV = 111; // -
  int IREM = 112; // -
  int LREM = 113; // -
  int FREM = 114; // -
  int DREM = 115; // -
  int INEG = 116; // -
  int LNEG = 117; // -
  int FNEG = 118; // -
  int DNEG = 119; // -
  int ISHL = 120; // -
  int LSHL = 121; // -
  int ISHR = 122; // -
  int LSHR = 123; // -
  int IUSHR = 124; // -
  int LUSHR = 125; // -
  int IAND = 126; // -
  int LAND = 127; // -
  int IOR = 128; // -
  int LOR = 129; // -
  int IXOR = 130; // -
  int LXOR = 131; // -
  int IINC = 132; // visitIincInsn
  int I2L = 133; // visitInsn
  int I2F = 134; // -
  int I2D = 135; // -
  int L2I = 136; // -
  int L2F = 137; // -
  int L2D = 138; // -
  int F2I = 139; // -
  int F2L = 140; // -
  int F2D = 141; // -
  int D2I = 142; // -
  int D2L = 143; // -
  int D2F = 144; // -
  int I2B = 145; // -
  int I2C = 146; // -
  int I2S = 147; // -
  int LCMP = 148; // -
  int FCMPL = 149; // -
  int FCMPG = 150; // -
  int DCMPL = 151; // -
  int DCMPG = 152; // -
  int IFEQ = 153; // visitJumpInsn
  int IFNE = 154; // -
  int IFLT = 155; // -
  int IFGE = 156; // -
  int IFGT = 157; // -
  int IFLE = 158; // -
  int IF_ICMPEQ = 159; // -
  int IF_ICMPNE = 160; // -
  int IF_ICMPLT = 161; // -
  int IF_ICMPGE = 162; // -
  int IF_ICMPGT = 163; // -
  int IF_ICMPLE = 164; // -
  int IF_ACMPEQ = 165; // -
  int IF_ACMPNE = 166; // -
  int GOTO = 167; // -
  int JSR = 168; // -
  int RET = 169; // visitVarInsn
  int TABLESWITCH = 170; // visiTableSwitchInsn
  int LOOKUPSWITCH = 171; // visitLookupSwitch
  int IRETURN = 172; // visitInsn
  int LRETURN = 173; // -
  int FRETURN = 174; // -
  int DRETURN = 175; // -
  int ARETURN = 176; // -
  int RETURN = 177; // -
  int GETSTATIC = 178; // visitFieldInsn
  int PUTSTATIC = 179; // -
  int GETFIELD = 180; // -
  int PUTFIELD = 181; // -
  int INVOKEVIRTUAL = 182; // visitMethodInsn
  int INVOKESPECIAL = 183; // -
  int INVOKESTATIC = 184; // -
  int INVOKEINTERFACE = 185; // -
  int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
  int NEW = 187; // visitTypeInsn
  int NEWARRAY = 188; // visitIntInsn
  int ANEWARRAY = 189; // visitTypeInsn
  int ARRAYLENGTH = 190; // visitInsn
  int ATHROW = 191; // -
  int CHECKCAST = 192; // visitTypeInsn
  int INSTANCEOF = 193; // -
  int MONITORENTER = 194; // visitInsn
  int MONITOREXIT = 195; // -
  int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
  int IFNULL = 198; // visitJumpInsn
  int IFNONNULL = 199; // -
}

到了这里,关于Springboot启动原理和自动配置原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot原理-自动配置-原理分析-源码跟踪

    SpringBootApplication 该注解标识在SpringBoot项目的启动类上,是SpringBoot中 最为重要 的注解,该注解由三个部分组成。 @SpringBootConfiguration:该注解与@Configuration注解作用一样,用来声明当前类为一个配置类 @ComponentScan:组件扫描,默认扫描当前启动类所在包及其子包 @EnableAutoConf

    2024年02月09日
    浏览(42)
  • SpringBoot自动配置原理简单分析

    说明:在SpringBoot项目中,我们添加了许许多多的注解,这些注解提高了开发效率。这是因为SpringBoot在项目启动时,帮我们自动装配了大量的Bean对象,可以通过分析源码查看自动装配的大致原理。 进入到启动类中的@SpringBootApplication注解中,该注解里面有七个注解,上面四个

    2024年02月09日
    浏览(42)
  • SpringBoot3自动配置原理

    遵循约定大约配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ioc容器 看一下我们前面写的代码有没有达到自动配置的效果呢? 没有自动,我们写了配置类,写了@Import注解,所以并没有达到自动配置的效果。那怎么办呢?接下来我们通过翻看源码的方

    2024年01月22日
    浏览(36)
  • springboot 原理分析之自动配置

             Condition 是在 Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操作。比如说,只有满足某一个条件才能创建这个 Bean ,否则就不创建。         SpringBoot 是如何知道要创建哪个 Bean 的?比如 SpringBoot 是如何知道要创建  RedisTemplate 

    2024年01月19日
    浏览(36)
  • 第九章 SpringBoot 自动配置原理 入门

    @SpringBootApplication -- @SpringBootConfiguration -- @EnableAutoConfiguration -- @ComponentScan 1.1 @SpringBootConfiguration @Configuration。代表当前是一个配置类 1.2 @ComponentScan 指定扫描哪些,Spring注解; 1.3 @EnableAutoConfiguration @EnableAutoConfiguration -- @AutoConfigurationPackage -- @Import(AutoConfigurationImportSelector.clas

    2024年02月13日
    浏览(42)
  • Spring(8) Springboot自动配置原理

    Springboot 的自动配置原理,是Springboot中最高频的一道面试题,也是Springboot框架最核心的思想。 首先我们看一张我总结的自动配置原理概览图: 下面,我们就根据这张图详细描述一下具体过程: 首先,我们来看一段代码: 上面就是一段普通的 Springboot 引导类代码,这里有一

    2024年02月12日
    浏览(42)
  • 第05天 SpringBoot自动配置原理

    ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:每天一个知识点 ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot自动配置原理 🖥️个人小站 :个人博客,欢迎大家访问 📚个人知识库: 知识库

    2024年02月12日
    浏览(31)
  • SpringBoot自动配置的原理是什么?

    自动配置的核心就在@SpringBootApplication注解上,SpringBootApplication这个注解底层包含了3个注解,分别是: @SpringBootConfiguration @ComponentScan @EnableAutoConfiguration @EnableAutoConfiguration这个注解才是自动配置的核心。 它封装了一个@Import注解,Import注解里面指定了一个ImportSelector接口的实现

    2023年04月24日
    浏览(36)
  • SpringBoot:自动配置源码底层原理分析

    声明:原文作者:yuan_404 配置文件到底能写什么?怎么写? SpringBoot 官方文档中有大量的配置,我们无法全部记住 ,下面我们就梳理一下最核心的几个部分进行讲解。 以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理; @Configuration(proxyBeanMethods = false) 表示

    2023年04月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包