SpringBoot应用的启动通常从main方法开始,其中最核心的是调用SpringApplication.run()方法:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
这行简单的代码背后隐藏着复杂的启动流程,SpringApplication.run()方法是整个SpringBoot应用启动的核心入口,它负责创建并配置Spring应用上下文、启动嵌入式服务器等一系列关键操作。
SpringBoot应用的启动流程可以大致分为以下几个主要阶段:
在启动过程中,涉及到多个核心组件:
SpringApplication.run()方法有多种重载形式,最常用的是:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String... args) {
return new SpringApplication(primarySources).run(args);
}
可以看到,最终会创建一个SpringApplication实例并调用其run()方法。
SpringApplication的构造函数会执行一系列初始化操作:
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用类型(REACTIVE, SERVLET, NONE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
在构造函数中,会通过WebApplicationType.deduceFromClasspath()方法推断应用类型:
static WebApplicationType deduceFromClasspath() {
// 判断是否存在REACTIVE相关类
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 判断是否存在SERVLET相关类
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
这里通过检查类路径中是否存在特定的类来判断应用类型:
SpringApplication会从META-INF/spring.factories文件中加载初始化器和监听器:
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();
// 从META-INF/spring.factories加载指定类型的类
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化这些类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames()方法会从所有META-INF/spring.factories文件中查找指定类型的实现类:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 查找所有META-INF/spring.factories资源
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 解析每个spring.factories文件
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
SpringApplication会尝试推断主应用类:
private Class<?> deduceMainApplicationClass() {
try {
// 获取当前线程的堆栈轨迹
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
// 返回包含main方法的类
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// 忽略异常
}
return null;
}
SpringApplication实例创建完成后,会调用其run()方法:
public ConfigurableApplicationContext run(String... args) {
// 记录启动开始时间
long startTime = System.nanoTime();
// 创建默认的应用上下文和异常报告器
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置无头模式
configureHeadlessProperty();
// 获取并启动应用监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 创建应用参数容器
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置忽略的Bean信息
configureIgnoreBeanInfo(environment);
// 打印Banner
Banner printedBanner = printBanner(environment);
// 创建应用上下文
context = createApplicationContext();
// 设置引导上下文
context.setBootstrapContext(bootstrapContext);
// 准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
refreshContext(context);
// 刷新后的处理
afterRefresh(context, applicationArguments);
// 计算并记录启动时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
// 记录启动完成日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 发布应用就绪事件
listeners.started(context, timeTakenToStartup);
// 调用所有Runner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 处理启动异常
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 发布应用运行中事件
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
// 处理就绪异常
if (context != null) {
context.close();
throw new IllegalStateException("Application run failed", ex);
}
throw new IllegalStateException("Application run failed", ex);
}
// 返回应用上下文
return context;
}
在run()方法开始时,会初始化并启动应用监听器:
private SpringApplicationRunListeners getRunListeners(String... args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
// SpringApplicationRunListeners类
public void starting(DefaultBootstrapContext bootstrapContext, @Nullable Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
return step;
});
}
SpringApplicationRunListener是SpringBoot应用启动过程中的核心监听器接口,它定义了应用启动各个阶段的回调方法。
run()方法会创建并准备应用参数和环境:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建并配置环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 应用属性转换服务
ConfigurationPropertySources.attach(environment);
// 发布环境准备就绪事件
listeners.environmentPrepared(bootstrapContext, environment);
// 绑定应用参数
bindToSpringApplication(environment);
// 确保是标准环境
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
// 配置属性源
ConfigurationPropertySources.attach(environment);
return environment;
}
SpringBoot应用启动时会打印Banner:
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
// 获取资源加载器
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(getClassLoader());
// 创建Banner打印器
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
// 打印控制台Banner
if (this.bannerMode == Banner.Mode.CONSOLE) {
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
// 打印日志Banner
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
Banner打印器会尝试从classpath下加载banner.txt或banner.gif等文件作为Banner:
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
Banner banner = getBanner(environment);
banner.printBanner(environment, sourceClass, out);
return banner;
}
private Banner getBanner(Environment environment) {
Banners banners = new Banners();
// 添加文本Banner
banners.addIfNotNull(getTextBanner(environment));
// 添加图像Banner
banners.addIfNotNull(getImageBanner(environment));
// 如果没有找到任何Banner,使用默认Banner
if (banners.hasAtLeastOneBanner()) {
return banners;
}
// 返回默认Banner
return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;
}
run()方法会创建并准备应用上下文:
protected ConfigurableApplicationContext createApplicationContext() {
// 根据应用类型创建不同的上下文
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable to create a default ApplicationContext, please specify an ApplicationContextClass",
ex);
}
}
// 实例化上下文
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
private void prepareContext(DefaultBootstrapContext bootstrapContext, 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);
}
// 添加单例Bean
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());
}
// 加载所有资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载主配置类
load(context, sources.toArray(new Object[0]));
// 发布上下文加载完成事件
listeners.contextLoaded(context);
}
run()方法中调用的refreshContext(context)会触发应用上下文的刷新:
private void refreshContext(ConfigurableApplicationContext context) {
// 如果需要刷新,则刷新上下文
if (this.registerShutdownHook) {
try {
// 注册关闭钩子,确保应用优雅关闭
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// 忽略安全管理器异常
}
}
// 刷新上下文
refresh(context);
}
protected void refresh(ConfigurableApplicationContext context) {
// 调用标准的上下文刷新方法
context.refresh();
}
refresh()方法是Spring应用上下文的核心方法,定义在AbstractApplicationContext中:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新上下文
prepareRefresh();
// 获取并刷新Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置Bean工厂
prepareBeanFactory(beanFactory);
try {
// 允许Bean工厂后置处理器对Bean定义进行后置处理
postProcessBeanFactory(beanFactory);
// 调用所有注册的Bean工厂后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册所有Bean后置处理器
registerBeanPostProcessors(beanFactory);
// 初始化消息源
initMessageSource();
// 初始化应用事件多播器
initApplicationEventMulticaster();
// 初始化其他特殊Bean
onRefresh();
// 检查并注册监听器
registerListeners();
// 实例化所有剩余的(非懒加载)单例
finishBeanFactoryInitialization(beanFactory);
// 完成刷新,发布相应事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免资源悬空
destroyBeans();
// 重置"active"标志
cancelRefresh(ex);
// 传播异常到调用者
throw ex;
}
finally {
// 重置公共缓存
resetCommonCaches();
}
}
}
在refresh()方法中,会准备并配置Bean工厂:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置Bean工厂的类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置Bean表达式解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 添加属性编辑器注册器
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加Bean后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 设置忽略的自动装配接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 注册可解析的依赖
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加ApplicationListener探测器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 添加LoadTimeWeaver探测器
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 设置临时类加载器进行类型匹配
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册默认环境Bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 注册系统属性和环境变量
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 注册系统环境
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
refresh()方法会调用所有注册的Bean工厂后置处理器:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 调用BeanDefinitionRegistryPostProcessor类型的处理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 检测LoadTimeWeaver并准备编织器
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法会处理所有BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 保存已经处理的处理器名称,避免重复处理
Set<String> processedBeans = new HashSet<>();
// 处理BeanDefinitionRegistry类型的工厂
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 区分普通的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 首先处理传入的BeanFactoryPostProcessor
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// 现在,处理在上下文中定义的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,调用实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序并调用
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 接下来,调用实现Ordered接口的BeanDefinitionRegistryPostProcessor
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序并调用
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 最后,调用所有其他的BeanDefinitionRegistryPostProcessor,直到不再有新的处理器出现
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
// 排序并调用
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 调用所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 调用普通的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 如果不是BeanDefinitionRegistry类型的工厂,直接调用所有BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 现在,调用在上下文中定义的所有BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 分离实现PriorityOrdered、Ordered和其他的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 跳过已处理的处理器
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,调用实现PriorityOrdered接口的BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接下来,调用实现Ordered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后,调用所有其他的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除缓存的合并Bean定义,因为后处理器可能修改了原始元数据
beanFactory.clearMetadataCache();
}
refresh()方法会注册所有Bean后置处理器:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
PostProcessorRegistrationDelegate.registerBeanPostProcessors()方法会注册并排序所有Bean后置处理器:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 获取所有Bean后置处理器的名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 注册BeanPostProcessorChecker,用于记录信息
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 分离实现PriorityOrdered、Ordered和其他的BeanPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,注册实现PriorityOrdered接口的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// 接下来,注册实现Ordered接口的BeanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 然后,注册所有其他的BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最后,注册所有内部BeanPostProcessor
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// 添加ApplicationListenerDetector以检测ApplicationListener Bean
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
refresh()方法会初始化消息源和事件多播器:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 检查是否存在用户定义的messageSource Bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 如果messageSource是HierarchicalMessageSource类型,设置父消息源
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// 只有在没有父消息源的情况下设置,避免覆盖用户设置
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// 创建并注册默认的DelegatingMessageSource
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 检查是否存在用户定义的applicationEventMulticaster Bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 创建并注册默认的SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
refresh()方法会调用onRefresh()方法初始化特殊Bean:
protected void onRefresh() throws BeansException {
// 对于Web应用上下文,这里会初始化Servlet上下文
// 子类可以重写此方法以初始化其他特殊Bean
}
然后注册事件监听器并完成刷新:
protected void registerListeners() {
// 注册静态指定的监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 从Bean工厂中获取所有ApplicationListener Bean并注册
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 发布早期应用事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化类型转换器
if (beanFactory.containsBean(TYPE_CONVERTER_BEAN_NAME)) {
beanFactory.addPropertyEditorRegistrar(
new BeanFactoryTypeConverter(beanFactory.getBean(TYPE_CONVERTER_BEAN_NAME, TypeConverter.class)));
}
// 初始化LoadTimeWeaverAware Bean
if (!beanFactory.getTempClassLoader().getClass().getName().contains("ContextTypeMatchClassLoader")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 冻结所有Bean定义,表明注册的Bean定义不会被修改或进一步后处理
beanFactory.freezeConfiguration();
// 实例化所有剩余的(非懒加载)单例
beanFactory.preInstantiateSingletons();
}
protected void finishRefresh() {
// 清除资源缓存
clearResourceCaches();
// 初始化生命周期处理器
initLifecycleProcessor();
// 注册生命周期处理器的回调
getLifecycleProcessor().onRefresh();
// 发布ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
在应用上下文刷新完成后,SpringBoot会启动嵌入式服务器:
// 在ServletWebServerApplicationContext类中
@Override
protected void onRefresh() {
super.onRefresh();
try {
// 创建并启动Web服务器
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 获取ServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 创建Web服务器
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
// 如果已经有Servlet上下文,初始化它
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
// 初始化属性源
initPropertySources();
}
protected ServletWebServerFactory getWebServerFactory() {
// 获取ServletWebServerFactory Bean名称
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " +
"ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " +
"ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
}
// 获取并返回ServletWebServerFactory Bean
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
SpringBoot提供了多种嵌入式服务器的实现,如Tomcat、Jetty和Undertow:
// TomcatServletWebServerFactory类
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 创建Tomcat实例
Tomcat tomcat = new Tomcat();
// 配置基本目录
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 配置连接器
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
// 配置Engine和Host
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// 准备上下文
prepareContext(tomcat.getHost(), initializers);
// 返回Web服务器包装器
return getTomcatWebServer(tomcat);
}
// JettyServletWebServerFactory类
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 创建Server实例
Server server = new Server();
// 配置连接器
ServerConnector connector = new ServerConnector(server);
if (this.port != null) {
connector.setPort(this.port);
}
server.addConnector(connector);
// 配置处理程序
configureHandler(server);
// 配置Session
if (this.session != null && this.session.getTimeout() != null) {
Duration timeout = this.session.getTimeout();
long seconds = timeout.getSeconds();
if (seconds >= 0) {
this.sessionTimeout = (int) seconds;
}
}
// 准备上下文
ServletContextHandler contextHandler = prepareContext(server, initializers);
// 返回Web服务器包装器
return new JettyWebServer(server, this.autoStart, contextHandler);
}
// UndertowServletWebServerFactory类
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 创建Undertow构建器
Undertow.Builder builder = createBuilder(getPort());
// 创建Servlet容器
DeploymentInfo servletBuilder = getDeploymentInfo(initializers);
DeploymentManager manager = defaultContainer.addDeployment(servletBuilder);
manager.deploy();
// 获取Servlet上下文
try {
ServletContext context = manager.start();
configureContext(context, initializers);
}
catch (ServletException ex) {
throw new WebServerException("Unable to start embedded Undertow server", ex);
}
// 添加Servlet部署到构建器
builder.deploy(servletBuilder);
// 创建并启动Undertow服务器
Undertow undertow = builder.build();
startDaemonAwaitThread(undertow);
// 返回Web服务器包装器
return new UndertowWebServer(undertow, this.autoStart, getPort() >= 0);
}
嵌入式服务器的配置可以通过多种方式进行定制:
// 通过配置属性定制
@Configuration
public class WebServerCustomizationConfiguration {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return factory -> {
// 定制Tomcat服务器
factory.addConnectorCustomizers(connector -> {
// 配置连接器
connector.setPort(8080);
connector.setMaxThreads(200);
connector.setMaxConnections(8192);
});
// 配置Tomcat引擎
factory.addEngineCustomizers(engine -> {
engine.setRealm(new MemoryRealm());
});
// 配置上下文
factory.addContextCustomizers(context -> {
context.setSessionTimeout(30);
});
};
}
@Bean
public WebServerFactoryCustomizer<JettyServletWebServerFactory> jettyCustomizer() {
return factory -> {
// 定制Jetty服务器
factory.addServerCustomizers(server -> {
// 配置Jetty服务器
server.setStopAtShutdown(true);
server.setStopTimeout(5000);
});
// 配置连接器
factory.addConnectorCustomizers(connector -> {
connector.setIdleTimeout(30000);
});
};
}
@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowCustomizer() {
return factory -> {
// 定制Undertow服务器
factory.addBuilderCustomizers(builder -> {
// 配置Undertow构建器
builder.setIoThreads(4);
builder.setWorkerThreads(20);
});
// 添加Servlet容器定制器
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
deploymentInfo.setSessionTimeout(30);
});
};
}
}
SpringBoot应用在启动过程中会发布多种事件:
// SpringApplicationRunListeners类
public void starting(DefaultBootstrapContext bootstrapContext, @Nullable Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
return step;
});
}
public void environmentPrepared(DefaultBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
doWithListeners("spring.boot.application.environment-prepared",
(listener) -> listener.environmentPrepared(bootstrapContext, environment),
(step) -> step.tag("configLocations", getConfigLocations(environment)));
}
public void contextPrepared(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-prepared",
(listener) -> listener.contextPrepared(context), null);
}
public void contextLoaded(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-loaded",
(listener) -> listener.contextLoaded(context), null);
}
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
doWithListeners("spring.boot.application.started",
(listener) -> listener.started(context, timeTaken), null);
}
public void running(ConfigurableApplicationContext context, Duration timeTaken) {
doWithListeners("spring.boot.application.running",
(listener) -> listener.running(context, timeTaken), null);
}
public void failed(ConfigurableApplicationContext context, Throwable exception) {
doWithListeners("spring.boot.application.failed",
(listener) -> listener.failed(context, exception), null);
}
应用事件监听器可以通过多种方式注册:
// 通过META-INF/spring.factories注册
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
// 通过@Bean方法注册
@Configuration
public class MyApplicationConfiguration {
@Bean
public ApplicationListener<ApplicationReadyEvent> readyListener() {
return event -> {
// 应用准备就绪后的处理逻辑
System.out.println("Application is ready!");
};
}
@Bean
public ApplicationListener<ContextRefreshedEvent> refreshedListener() {
return event -> {
// 上下文刷新后的处理逻辑
System.out.println("Context is refreshed!");
};
}
}
// 通过@Component和@EventListener注解注册
@Component
public class MyApplicationListener {
@EventListener
public void handleContextRefreshed(ContextRefreshedEvent event) {
// 处理上下文刷新事件
System.out.println("Context refreshed: " + event.getApplicationContext());
}
@EventListener
public void handleApplicationReady(ApplicationReadyEvent event) {
// 处理应用就绪事件
System.out.println("Application ready: " + event.getApplicationContext());
}
@EventListener
public void handleApplicationFailed(ApplicationFailedEvent event) {
// 处理应用失败事件
System.out.println("Application failed: " + event.getException().getMessage());
}
}
事件监听器可以通过实现Ordered接口或使用@Order注解来指定处理顺序:
// 实现Ordered接口
@Component
public class MyOrderedListener implements ApplicationListener<ApplicationReadyEvent>, Ordered {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// 处理应用就绪事件
System.out.println("MyOrderedListener: Application is ready!");
}
@Override
public int getOrder() {
// 返回优先级,值越小优先级越高
return Ordered.HIGHEST_PRECEDENCE + 10;
}
}
// 使用@Order注解
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
public class MyAnnotatedListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// 处理应用就绪事件
System.out.println("MyAnnotatedListener: Application is ready!");
}
}
SpringBoot的自动配置是基于条件注解实现的:
// 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 {};
}
AutoConfigurationImportSelector会从META-INF/spring.factories文件中加载所有自动配置类:
// AutoConfigurationImportSelector类
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 获取自动配置元数据
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 获取自动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
// 返回自动配置类名数组
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
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 = filter(configurations, autoConfigurationMetadata);
// 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回自动配置条目
return new AutoConfigurationEntry(configurations, exclusions);
}
SpringBoot使用多种条件注解来控制自动配置的生效条件:
// ConditionalOnClass注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
/**
* 指定类必须存在于类路径上
*/
Class<?>[] value() default {};
/**
* 指定类名必须存在于类路径上
*/
String[] name() default {};
}
// ConditionalOnMissingBean注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
/**
* 指定必须不存在的Bean类型
*/
Class<?>[] value() default {};
/**
* 指定必须不存在的Bean名称
*/
String[] name() default {};
/**
* 指定查找Bean的搜索范围
*/
SearchStrategy search() default SearchStrategy.ALL;
}
// ConditionalOnProperty注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
/**
* 指定属性名前缀
*/
String prefix() default "";
/**
* 指定属性名
*/
String[] name() default {};
/**
* 指定属性值必须等于的值
*/
String havingValue() default "";
/**
* 指定当属性不存在时是否匹配
*/
boolean matchIfMissing() default false;
}
自动配置类通常包含多个@Bean方法,并使用条件注解控制这些方法的生效条件:
// DataSourceAutoConfiguration类
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSourceInitializerInvoker dataSourceInitializerInvoker(
DataSource dataSource, DataSourceProperties properties) {
// 创建数据源初始化调用器
return new DataSourceInitializerInvoker(dataSource, properties);
}
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
static class EmbeddedDatabaseConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
// 创建嵌入式数据源
return properties.initializeDataSourceBuilder().build();
}
}
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@Import({ Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class,
Generic.class, DataSourceJmxConfiguration.class })
static class PooledDataSourceConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties) {
// 创建连接池数据源
return properties.initializeDataSourceBuilder().build();
}
}
// 其他内部配置类和方法...
}
SpringBoot应用启动时会解析命令行参数:
// DefaultApplicationArguments类
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
@Override
public String[] getPropertyNames() {
synchronized (this) {
if (this.propertyNames == null) {
// 初始化属性名数组
this.propertyNames = extractPropertyNames(getOptionNames());
}
return this.propertyNames.clone();
}
}
private String[] extractPropertyNames(Set<String> optionNames) {
// 提取属性名
return StringUtils.toStringArray(optionNames);
}
@Override
public boolean containsProperty(String name) {
return getOptionNames().contains(name);
}
@Override
public Object getProperty(String name) {
return getOptionValues(name);
}
}
命令行参数的优先级高于其他配置源:
// ConfigFileApplicationListener类
private void addCommandLineProperties(ConfigurableEnvironment environment, String[] args) {
if (args.length > 0) {
// 创建命令行属性源
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
CommandLinePropertySource<?> source = new SimpleCommandLinePropertySource(args);
// 移除默认的命令行属性源
if (environment.getPropertySources().contains(name)) {
environment.getPropertySources().replace(name, source);
}
else {
// 添加命令行属性源,优先级最高
environment.getPropertySources().addFirst(source);
}
}
}
开发者可以通过实现ApplicationRunner或CommandLineRunner接口来处理命令行参数:
// 实现CommandLineRunner接口
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 处理命令行参数
System.out.println("Command line arguments:");
for (String arg : args) {
System.out.println("- " + arg);
}
// 可以在这里执行应用启动后的初始化操作
}
}
// 实现ApplicationRunner接口
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 处理应用参数
System.out.println("Application arguments:");
// 获取非选项参数
List<String> nonOptionArgs = args.getNonOptionArgs();
System.out.println("Non-option arguments: " + nonOptionArgs);
// 获取选项参数
Set<String> optionNames = args.getOptionNames();
for (String optionName : optionNames) {
List<String> optionValues = args.getOptionValues(optionName);
System.out.println("Option '" + optionName + "': " + optionValues);
}
// 可以在这里执行应用启动后的初始化操作
}
}
SpringBoot应用启动过程中的异常会被捕获并处理:
// SpringApplication类
private void handleRunFailure(ConfigurableApplicationContext context, Throwable ex,
SpringApplicationRunListeners listeners) {
try {
try {
// 发布应用失败事件
if (listeners != null) {
listeners.failed(context, ex);
}
}
catch (Throwable ex2) {
logger.error("Error handling failed event", ex2);
}
// 记录启动失败日志
if (context != null) {
context.close();
}
// 报告异常
reportFailure(getExceptionReporters(context), ex);
}
catch (Throwable ex3) {
logger.error("Unable to close ApplicationContext", ex3);
}
// 重新抛出异常
ReflectionUtils.rethrowRuntimeException(ex);
}
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters, Throwable failure) {
try {
// 尝试使用异常报告器报告异常
if (!exceptionReporters.isEmpty()) {
boolean reported = false;
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
reported = true;
break;
}
}
// 如果没有报告器处理异常,记录错误日志
if (!reported && logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
}
在handleRunFailure
方法中,除了发布应用失败事件和关闭上下文外,reportFailure
方法负责将异常信息以更友好的方式呈现。Spring Boot通过SpringBootExceptionReporter
接口的实现类来完成这一任务,常见的实现包括DefaultErrorPageExceptionReporter
等。
private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters, Throwable failure) {
try {
if (!exceptionReporters.isEmpty()) {
boolean reported = false;
for (SpringBootExceptionReporter reporter : exceptionReporters) {
if (reporter.reportException(failure)) {
reported = true;
break;
}
}
if (!reported && logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
}
}
} catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error reporting failure", ex);
}
if (logger.isErrorEnabled()) {
logger.error("Application run failed", failure);
}
}
}
上述代码中,会依次尝试让每个SpringBootExceptionReporter
处理异常。如果有任何一个报告器处理成功(即reportException
方法返回true
),则认为异常已被妥善处理;若所有报告器都无法处理,且日志级别允许记录错误,就会直接记录异常信息到日志中。
以DefaultErrorPageExceptionReporter
为例,它主要用于Web应用场景,会尝试生成一个包含错误信息的HTML页面。在生成错误页面时,它会获取异常的详细堆栈信息、错误类型等内容,并结合Spring Boot默认的错误页面模板,将这些信息渲染到页面上。当应用启动过程中出现异常时,若满足一定条件(如在Web环境下),用户访问应用时就能看到这个详细的错误页面,而不是晦涩难懂的堆栈跟踪信息。
FailureAnalyzers
类在异常分析过程中扮演着关键角色。它负责从类路径中加载所有实现了FailureAnalyzer
接口的类,并按照一定顺序对异常进行分析。
public class FailureAnalyzers {
private final List<FailureAnalyzer> analyzers;
private final Log logger;
public FailureAnalyzers(ClassLoader classLoader, Log logger) {
this(classLoader, null, logger);
}
public FailureAnalyzers(ClassLoader classLoader, List<FailureAnalyzer> analyzers, Log logger) {
this.logger = logger;
List<FailureAnalyzer> loadedAnalyzers = (analyzers != null) ? new ArrayList<>(analyzers)
: SpringFactoriesLoader.loadFactories(FailureAnalyzer.class, classLoader);
AnnotationAwareOrderComparator.sort(loadedAnalyzers);
this.analyzers = Collections.unmodifiableList(loadedAnalyzers);
}
public FailureAnalysis analyze(Throwable failure) {
Throwable rootFailure = findRootCause(failure);
if (rootFailure != null) {
for (FailureAnalyzer analyzer : this.analyzers) {
try {
FailureAnalysis analysis = analyzer.analyze(rootFailure);
if (analysis != null) {
return analysis;
}
} catch (Throwable ex) {
if (this.logger.isDebugEnabled()) {
String message = ex.getMessage();
message = (message != null) ? message : "no error message";
this.logger.debug("FailureAnalyzer " + analyzer.getClass().getName()
+ " failed to analyze cause: " + message, ex);
}
}
}
}
return null;
}
private Throwable findRootCause(Throwable failure) {
Throwable root = failure;
Throwable cause;
while ((cause = root.getCause()) != null) {
root = cause;
}
return root;
}
}
首先,在构造函数中,FailureAnalyzers
通过SpringFactoriesLoader
从META-INF/spring.factories
文件中加载所有的FailureAnalyzer
实现类,并使用AnnotationAwareOrderComparator
进行排序,确保按照优先级顺序处理。
在analyze
方法中,它会先找到异常的根本原因,然后依次让每个FailureAnalyzer
尝试分析该根本原因。每个FailureAnalyzer
实现类都有自己的分析逻辑,比如判断异常类型是否是自己能处理的,如果是,则根据异常信息生成一个FailureAnalysis
对象,该对象包含了错误描述和解决建议。一旦有FailureAnalyzer
成功生成FailureAnalysis
对象,就会立即返回,不再继续尝试其他分析器。
例如,DataSourceUnavailableFailureAnalyzer
专门用于分析数据库连接相关的异常。当应用启动时无法连接到数据库,抛出SQLException
等异常时,DataSourceUnavailableFailureAnalyzer
会判断异常是否属于数据库连接失败相关类型。如果是,它会从异常信息中提取出数据库URL、用户名等关键信息,并生成包含错误原因(如“无法连接到指定的数据库URL”)和解决建议(如“检查数据库URL是否正确,确保数据库服务已启动”)的FailureAnalysis
对象,帮助开发者快速定位和解决问题。
当Spring容器中存在多个相同类型或名称的Bean定义时,就会引发Bean定义冲突问题。主要有两种常见情况:
@Component
、@Service
、@Repository
等注解标注的类,或通过@Bean
方法定义的Bean,它们的类型相同。例如,定义了两个UserService
类:@Service
public class UserService {
// 业务逻辑
}
@Service
public class AnotherUserService implements UserService {
// 另一种实现的业务逻辑
}
当在其他类中通过@Autowired
注入UserService
时,Spring容器无法确定应该注入哪一个,就会抛出NoUniqueBeanDefinitionException
异常。
@Bean
方法显式指定了相同的Bean名称,也会产生冲突。比如:@Configuration
public class AppConfig {
@Bean("commonBean")
public Object bean1() {
return new Object();
}
@Bean("commonBean")
public Object bean2() {
return new Object();
}
}
此时会抛出BeanDefinitionOverrideException
异常。
解决方案:
@Primary
注解:在多个同类型Bean中,将其中一个标注为@Primary
,表示该Bean为首选注入对象。例如,在上述UserService
的例子中,可以将其中一个UserService
类标注为@Primary
:@Service
@Primary
public class UserService {
// 业务逻辑
}
这样在注入UserService
时,Spring会优先选择带有@Primary
注解的Bean。
@Qualifier
注解:通过@Qualifier
指定具体的Bean名称或限定条件。在注入时明确指出要使用的Bean,如:@Service
public class UserService {
// 业务逻辑
}
@Service
public class AnotherUserService {
// 业务逻辑
}
@Service
public class UserController {
private final UserService userService;
@Autowired
public UserController(@Qualifier("userService") UserService userService) {
this.userService = userService;
}
}
这里通过@Qualifier("userService")
指定了要注入的具体UserService
Bean。
spring.main.allow-bean-definition-overriding=true
:在application.properties
或application.yml
中设置该属性,允许Bean定义覆盖。但这种方式可能会导致一些难以排查的问题,不建议在生产环境中使用,仅用于开发调试阶段临时解决冲突。当Spring Boot应用使用嵌入式服务器(如Tomcat、Jetty、Undertow)启动时,会尝试绑定到指定的端口。如果该端口已经被其他进程占用,就会抛出类似于Address already in use: bind
的异常。例如,默认情况下,Spring Boot的Web应用会尝试绑定到8080端口,如果8080端口已被其他Web服务占用,应用启动就会失败。
解决方案:
application.properties
或application.yml
文件中,通过server.port
属性指定其他未被占用的端口。如在application.properties
中设置:server.port=8081
或在application.yml
中设置:
server:
port: 8081
netstat -ano | findstr :端口号
查看占用端口的进程ID,然后使用taskkill /pid 进程ID /f
关闭进程;在Linux下使用lsof -i :端口号
查看进程,使用kill -9 进程ID
关闭进程)找到并关闭占用该端口的应用程序。server.port
设置为0
,此时Spring Boot会随机分配一个可用的端口。不过这种方式在需要明确访问端口的场景下不太适用,一般用于测试环境或对端口没有固定要求的情况。Spring Boot的自动配置机制会根据类路径下的依赖和配置属性,自动配置应用所需的各种组件。但当多个自动配置类都尝试配置同一组件,或者自动配置类与开发者自定义配置产生冲突时,就会出现自动配置冲突问题。例如,同时引入了两个不同的数据访问框架依赖,它们各自的自动配置类都想配置数据源相关组件,就可能导致冲突。
解决方案:
@SpringBootApplication
的exclude
属性:在@SpringBootApplication
注解中,通过exclude
属性排除不需要的自动配置类。比如,不想使用Spring Boot默认的数据库连接池自动配置,可以这样写:@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@ConditionalOnMissingBean
、@ConditionalOnClass
、@ConditionalOnProperty
等条件注解,明确指定Bean创建的条件,避免冲突。例如,只有当类路径中不存在特定的数据源实现类时,才创建自定义的数据源Bean:@Configuration
public class MyDataSourceConfig {
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource customDataSource() {
// 自定义数据源创建逻辑
}
}
exclusions
排除不必要的依赖。例如,在Maven项目中:<dependency>
<groupId>com.examplegroupId>
<artifactId>example-dependencyartifactId>
<version>1.0.0version>
<exclusions>
<exclusion>
<groupId>冲突依赖的groupIdgroupId>
<artifactId>冲突依赖的artifactIdartifactId>
exclusion>
exclusions>
dependency>
类路径问题主要包括缺少必要的依赖类,或者依赖类的版本不兼容,从而导致ClassNotFoundException
或NoClassDefFoundError
等异常。例如,项目中使用了某个第三方库的特定功能,但没有引入对应的依赖;或者引入的多个依赖之间存在版本冲突,导致某些类无法正确加载。
解决方案:
pom.xml
或Gradle的build.gradle
)中添加正确的依赖。比如,在Maven项目中添加Jackson
依赖:<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.0version>
dependency>
dependencyManagement
统一管理依赖版本,避免不同依赖引入不一致的版本。例如,在Maven的pom.xml
中:<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.examplegroupId>
<artifactId>common-dependencyartifactId>
<version>1.0.0version>
dependency>
dependencies>
dependencyManagement>
或者通过exclusions
排除冲突版本的依赖,再手动引入正确版本的依赖。
File -> Invalidate Caches / Restart
),然后重新构建项目,确保类路径正确更新。配置错误涵盖多种情况,包括配置文件格式错误、属性值类型不匹配、属性名拼写错误、配置层级结构混乱等。在Spring Boot中,配置信息通常从application.properties
、application.yml
等文件加载,并通过@ConfigurationProperties
等机制绑定到Java类中。
例如,在application.yml
文件中,错误地缩进配置层级:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 123456
这里url
、username
、password
的缩进与datasource
同级,不符合YAML格式要求,会导致解析错误。
又如,属性值类型不匹配的情况:
myapp:
max-connections: "ten"
假设MyAppConfig
类中max-connections
对应的属性是int
类型,那么将字符串"ten"
绑定到int
类型属性时就会失败。
解决方案:
application.properties
和application.yml
文件的格式正确。对于application.yml
,严格遵循YAML的缩进规则,每个层级的缩进保持一致;对于application.properties
,属性名和值之间使用正确的=
分隔,且不包含非法字符。可以借助IDE的语法检查功能,及时发现格式错误。Date
类型时,可以使用@DateTimeFormat
注解进行格式化转换。@ConfigurationProperties
注解的prefix
和属性名一致。对于复杂的配置类,可以使用IDE的重构功能修改属性名,避免手动修改导致的拼写错误。@Validated
注解对配置类进行验证。在配置类的属性上添加验证注解,如@NotNull
、@Min
、@Max
等,在配置绑定完成后,Spring会自动对配置进行验证,若不满足验证条件,则会抛出异常,提示配置错误信息。例如:import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties(prefix = "myapp")
@Validated
public class MyAppConfig {
@NotBlank
private String name;
@NotNull
@Positive
private int age;
// 省略getter和setter
}
这样当配置中的name
为空字符串,或者age
为负数或null
时,就会在启动时抛出验证异常,帮助开发者快速定位配置错误。
数据库连接失败是Spring Boot应用启动时常见的问题之一,主要原因包括数据库URL错误、用户名密码错误、数据库驱动版本不兼容、数据库服务未启动等。
例如,数据库URL中的IP地址、端口号、数据库名称写错:
spring:
datasource:
url: jdbc:mysql://192.168.1.100:3307/mydb
username: root
password: 123456
如果实际的数据库IP是192.168.1.101
,或者端口是3306
,就会导致连接失败。
又或者使用的数据库驱动版本与数据库不兼容,比如使用较旧的MySQL驱动连接新版本的MySQL数据库,可能会出现不支持的协议等问题。
解决方案:
application.properties
或application.yml
中的数据库连接配置,确保数据库URL、用户名、密码正确无误。可以尝试使用数据库客户端工具(如Navicat、DBeaver)连接数据库,验证配置信息是否能正常连接。解决方案:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.26version>
dependency>
如果使用的是HikariCP连接池(Spring Boot默认),确保其版本与数据库驱动兼容。例如,HikariCP 4.x版本与MySQL Connector/J 8.x兼容。
systemctl status mysql
如果服务未启动,使用相应命令启动服务:
systemctl start mysql
验证网络连接:确保应用服务器能够访问数据库服务器,检查网络连接是否正常,防火墙是否放行数据库端口。例如,MySQL默认使用3306端口,需要确保该端口在防火墙中是开放的。
配置连接属性:在数据库URL中添加必要的连接参数,如字符集、时区等。例如,对于MySQL:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
其中,useUnicode
和characterEncoding
确保字符集正确,useSSL
设置是否使用SSL连接,serverTimezone
设置时区以避免时间相关问题。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnectionTest {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "123456";
try (Connection connection = DriverManager.getConnection(url, username, password)) {
System.out.println("数据库连接成功!");
} catch (SQLException e) {
System.out.println("数据库连接失败:" + e.getMessage());
e.printStackTrace();
}
}
}
Spring Boot通过组件扫描(Component Scanning)自动发现并注册应用中的组件(如@Component
、@Service
、@Repository
等注解标注的类)。当组件扫描配置不正确时,可能导致组件未被正确注册,从而在运行时出现NoSuchBeanDefinitionException
等异常。
常见原因:
@SpringBootApplication
(或@ComponentScan
)指定的扫描包路径下。默认情况下,Spring Boot会扫描@SpringBootApplication
所在类的同级包及其子包。@ComponentScan
注解,排除了需要扫描的包或类。解决方案:
@SpringBootApplication
所在类的同级包或子包中,或者通过@ComponentScan
显式指定扫描路径。例如:@SpringBootApplication
@ComponentScan(basePackages = "com.example.myapp")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
这里指定了扫描com.example.myapp
包及其子包。
@ComponentScan
的excludeFilters
属性,确保没有错误地排除了需要的组件。例如:@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.example.myapp.excluded.*")
})
确保正则表达式或其他过滤条件不会意外排除关键组件。
@Configuration
类和@Bean
方法手动注册。例如:@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
依赖注入是Spring框架的核心特性之一,但在实际应用中可能会遇到各种问题,如循环依赖、注入类型不匹配、找不到合适的Bean等。
常见问题及解决方案:
BeanCurrentlyInCreationException
异常。例如:@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
// 构造函数或方法使用serviceB
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
// 构造函数或方法使用serviceA
}
解决方案:
@Lazy
注解:在其中一个依赖上使用@Lazy
注解,延迟加载该依赖,直到实际使用时才创建。例如:@Service
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
BeanNotOfRequiredTypeException
异常。例如:@Service
public class MyService {
// 业务逻辑
}
@Service
public class MyController {
@Autowired
private AnotherService myService; // 类型不匹配,AnotherService与MyService不兼容
}
解决方案:
检查注入点的类型声明,确保与实际Bean的类型一致。
如果需要注入接口的实现类,确保实现类正确实现了该接口,并且在容器中注册为该接口类型的Bean。
找不到合适的Bean:当没有找到符合条件的Bean时,会抛出NoSuchBeanDefinitionException
异常。例如:
@Service
public class MyService {
@Autowired
private MyRepository repository; // 容器中没有MyRepository类型的Bean
}
解决方案:
MyRepository
类被正确标注为@Repository
或其他组件注解,并且在组件扫描路径内。@Bean
方法正确注册。在Spring Boot应用中,版本冲突是常见的问题,特别是当引入多个第三方依赖时,可能会导致依赖库的不同版本之间存在兼容性问题。例如,不同的依赖可能引用了同一库的不同版本,导致类加载冲突或方法调用异常。
常见症状:
NoClassDefFoundError
或ClassNotFoundException
:表示找不到某个类,可能是因为依赖版本不一致导致某些类被覆盖或缺失。NoSuchMethodError
:表示调用了不存在的方法,通常是由于依赖库版本不兼容,方法签名发生了变化。IllegalArgumentException
、NullPointerException
等,可能是由于不同版本的库行为不一致导致的。解决方案:
mvn dependency:tree
在Gradle中使用:
gradle dependencies
dependencyManagement
(Maven)或resolutionStrategy
(Gradle)统一管理依赖版本,确保同一库只使用一个版本。例如,在Maven的pom.xml
中:<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.3.18version>
dependency>
dependencies>
dependencyManagement>
<dependency>
<groupId>com.examplegroupId>
<artifactId>example-libraryartifactId>
<version>1.0.0version>
<exclusions>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
exclusion>
exclusions>
dependency>
spring-boot-starter-parent
提供了一组默认的依赖版本,这些版本经过了测试,相互兼容。尽量使用Spring Boot推荐的版本,避免手动指定版本号,除非必要。当Bean的初始化过程中发生错误时,会导致应用启动失败。常见的原因包括:
解决方案:
@PostConstruct
注解的方法或InitializingBean
接口的afterPropertiesSet
方法没有抛出异常。例如:@Service
public class MyService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑,确保不会抛出异常
}
}
检查依赖组件:确保Bean依赖的其他组件已经正确初始化。可以通过日志或调试工具查看初始化顺序,找出依赖关系中的问题。
验证配置属性:确保注入到Bean中的配置属性有效且完整。可以使用@Validated
注解和JSR-303验证注解对配置属性进行验证。
使用@DependsOn
注解:如果Bean之间存在隐式依赖关系,可以使用@DependsOn
注解显式指定依赖顺序。例如:
@Service
@DependsOn("dataSource")
public class MyService {
// 业务逻辑
}
这里确保dataSource
Bean在MyService
之前初始化。
当遇到Spring Boot应用启动失败的问题时,可以使用以下调试技巧来快速定位和解决问题:
在application.properties
或application.yml
中添加以下配置,启用Spring的调试日志:
logging.level.root=INFO
logging.level.org.springframework=DEBUG
或在application.yml
中:
logging:
level:
root: INFO
org.springframework: DEBUG
这样可以获得更详细的启动过程日志,帮助分析问题所在。
在IDE中设置断点,逐步调试应用的启动过程。特别是在SpringApplication.run()
方法和关键组件的初始化方法中设置断点,观察变量值和执行流程,找出异常发生的位置。
--debug
参数在启动应用时添加--debug
参数,可以启用调试模式,输出更多的调试信息:
java -jar myapp.jar --debug
如果怀疑某个自动配置类导致了问题,可以使用@SpringBootApplication
的exclude
属性暂时禁用该自动配置类,观察应用是否能正常启动:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
在复杂的应用中,可以使用条件断点,只在满足特定条件时暂停执行。例如,在异常抛出的代码行设置条件断点,当特定的异常类型或条件满足时触发断点。
确保应用运行的环境配置正确,包括系统变量、环境变量、配置文件等。可以使用以下代码在应用启动时打印当前的环境配置:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MyApplication.class, args);
Environment env = context.getEnvironment();
System.out.println("Active profiles: " + Arrays.asList(env.getActiveProfiles()));
System.out.println("Application properties: " + env.getPropertySources());
}
}
Spring Boot应用启动失败可能由多种原因导致,包括配置错误、依赖问题、组件扫描问题、数据库连接问题等。通过深入理解Spring Boot的启动机制和常见错误模式,结合有效的调试技巧,可以快速定位和解决启动问题。
在排查问题时,建议按照以下步骤进行:
通过不断积累经验和掌握有效的排查方法,可以更加高效地解决Spring Boot应用启动过程中遇到的各种问题。