一起学习Spring boot 2.1.X | 第十三篇:异常统一类

本文介绍如何在Spring MVC中配置异常处理,通过设置application属性和创建UnifyException类,实现对NoHandlerFoundException和其他异常的统一处理和日志记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.application

#Exception
spring.mvc.throwExceptionIfNoHandlerFound=true

2.创建异常类,UnifyException

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 异常统一返回界面
 * 作者:我是沐沫
 */
@RestControllerAdvice
public class UnifyException {

    private final static Logger logger = LoggerFactory.getLogger(UnifyException.class);

    @ExceptionHandler(Exception.class)
    public void exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception e){
        if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) {
            logger.info("400:" + request.getRequestURL() + " ,Error:" + e.getMessage());
        } else {
            logger.info("500:" + request.getRequestURL() + " ,Error:" + e.getMessage());
        }
    }

}

注:application必须添加,自己试验条件

<think>首先,用户的问题是:“我想解决Spring Boot应用启动时因Bean定义冲突导致的上下文初始化失败问题 请问Spring Boot application failed to start due to BeanDefinitionOverrideException for dataSource bean defined in DruidDataSourceAutoConfigure and DynamicDataSourceAutoConfiguration” 用户提到了一个具体的错误:BeanDefinitionOverrideException,涉及dataSource bean在DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration中的冲突。 现在,回顾系级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层:回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 参考站内引用:提供了几个引用,但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我应该基于用户的问题来回答,而不是直接引用这些内容。用户的问题是Bean定义冲突,所以引用可能相关,但需要适配。 用户的问题是关于BeanDefinitionOverrideException的,具体是dataSource bean在DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration之间的冲突。DruidDataSourceAutoConfigure是阿里巴巴Druid数据源的自动配置类,DynamicDataSourceAutoConfiguration可能是用户自定义的或第三方库的动态数据源配置。 关键点:Spring Boot默认允许bean定义覆盖,但默认情况下,Spring Boot 2.1+禁止bean定义覆盖,除非显式启用。 错误原因:两个配置类都试图定义一个名为dataSource的bean,导致冲突。 解决方案: 1. **禁用bean定义覆盖**:在application.properties中设置`spring.main.allow-bean-definition-overriding=true`。但这可能不是最佳实践,因为它隐藏了问题。 2. **排除不必要的自动配置**:在启动类上使用`@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})`,但需要小心,因为可能破坏功能。 3. **自定义数据源配置**:确保只有一个配置类定义dataSource bean。可能用户需要调整DynamicDataSourceAutoConfiguration来避免冲突。 4. **使用别名或条件化配置**:在配置中使用`@Conditional`注解来控制bean的创建。 基于引用: - 引用[3]提到在启动类添加`exclude = {DataSourceAutoConfiguration.class}`来排除数据源自动配置。 - 引用[4]讨论了数据库连接池问题,但可能与bean定义冲突相关。 - 用户错误涉及Druid和DynamicDataSource,所以可能用户使用了动态数据源(如多数据源),而Druid的自动配置冲突了。 结构化回答: 1. **解释问题原因**:简要说明BeanDefinitionOverrideException是什么,为什么发生。 2. **提供解决方案**:逐步给出解决步骤。 3. **生成相关问题**:在回答末尾添加相关问题。 使用中文回答。 确保LaTeX格式正确:用户的问题中没有数学表达式,所以可能不需要,但如果有,就用$...$。 现在,构建回答: - 开头:确认问题。 - 原因分析:两个自动配置类都定义了dataSource bean。 - 解决方案: a. 允许bean定义覆盖(不推荐)。 b. 排除冲突的自动配置类。 c. 自定义数据源配置。 - 示例代码:提供启动类排除的示例。 - 引用:自然地添加引用标识。例如,引用[3]提到排除DataSourceAutoConfiguration。 生成相关问题:例如,关于如何配置多数据源、Spring Boot自动配置原理等。 最终回答结构: 1. 问题解释 2. 解决方案步骤 3. 相关问题</think>### Spring Boot应用启动时Bean定义冲突解决方案 您遇到的问题是由于Spring Boot应用启动时,`dataSource` bean在自动配置类`DruidDataSourceAutoConfigure`(来自阿里巴巴Druid连接池)和`DynamicDataSourceAutoConfiguration`(可能来自您的自定义或第三方动态数据源库)中重复定义,导致`BeanDefinitionOverrideException`错误。Spring Boot默认禁止bean定义覆盖(从2.1版本开始),当多个配置类试图注册同名bean时,会抛出此异常[^1]。下面我将一步步解释原因并提供可靠解决方案,确保应用正常启动。 #### 问题原因分析 - **核心冲突**:Spring Boot的自动配置机制(如`DataSourceAutoConfiguration`)会尝试创建默认数据源bean(名为`dataSource`)。同时: - `DruidDataSourceAutoConfigure`(Druid专用)在类路径检测到Druid时自动激活,并注册一个`dataSource` bean。 - `DynamicDataSourceAutoConfiguration`(用于多数据源场景)也尝试注册同名bean,导致冲突。 - **错误表现**:启动日志会显示类似错误: ``` BeanDefinitionOverrideException: Cannot register bean definition for 'dataSource' since there is already DruidDataSourceAutoConfigure & DynamicDataSourceAutoConfiguration bound ``` - **根本原因**:Spring Boot的`spring.main.allow-bean-definition-overriding`属性默认为`false`,禁止bean覆盖[^3]。 #### 分步解决方案 以下是三种可靠解决方案,按推荐顺序排列(优先推荐方案2): **方案1: 允许bean定义覆盖(快速修复,但非最佳)** 在`application.properties`或`application.yml`中设置允许bean覆盖。此方法简单,但可能隐藏潜在配置问题,建议仅用于临时调试。 ```properties # application.properties spring.main.allow-bean-definition-overriding=true ``` 或 ```yaml # application.yml spring: main: allow-bean-definition-overriding: true ``` **说明**:此设置强制Spring允许后定义的bean覆盖先定义的bean,但可能引入其他冲突[^3]。 **方案2: 排除冲突的自动配置类(推荐)** 在启动类上使用`@SpringBootApplication`的`exclude`属性,排除Druid或默认数据源的自动配置。确保只保留一个数据源配置源。 ```java import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, // 排除Spring Boot默认数据源配置 DruidDataSourceAutoConfigure.class // 排除Druid自动配置(根据需要二选一) }) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` **步骤说明**: 1. 如果您的动态数据源(`DynamicDataSourceAutoConfiguration`)已处理所有数据源逻辑,则排除`DataSourceAutoConfiguration.class`和`DruidDataSourceAutoConfigure.class`。 2. 如果仍需Druid连接池,但想用动态数据源管理,则只排除`DataSourceAutoConfiguration.class`,并确保`DynamicDataSourceAutoConfiguration`优先加载(例如通过`@Order`注解)。 3. **验证**:启动应用后检查日志,确认无`BeanDefinitionOverrideException`错误[^3][^4]。 **方案3: 自定义数据源配置(根治冲突)** 完全禁用自动配置,手动定义数据源bean。这适用于复杂多数据源场景。 1. 在启动类排除所有相关自动配置: ```java @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class }) public class Application { ... } ``` 2. 创建一个配置类(如`DataSourceConfig.java`),手动注册数据源bean: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.alibaba.druid.pool.DruidDataSource; import your.package.DynamicDataSource; // 替换为您的动态数据源类 @Configuration public class DataSourceConfig { @Bean public DataSource dataSource() { // 示例:使用动态数据源(根据需求调整) DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setDefaultTargetDataSource(druidDataSource()); return dynamicDataSource; } @Bean public DruidDataSource druidDataSource() { DruidDataSource ds = new DruidDataSource(); ds.setUrl("jdbc:mysql://localhost:3306/db"); ds.setUsername("root"); ds.setPassword("password"); return ds; } } ``` **优势**:完全控制bean创建,避免自动配置冲突。需确保依赖正确(如Druid坐标在`pom.xml`中)[^4]。 #### 注意事项 - **依赖检查**:确认`pom.xml`中未重复引入数据源依赖。例如,Druid应仅有一个依赖项: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> ``` - **配置优先级**:动态数据源配置应优先于自动配置加载(使用`@Order(Ordered.HIGHEST_PRECEDENCE)`)。 - **日志分析**:启动失败时检查完整日志,定位冲突bean的源头[^2][^5]。 - **最佳实践**:在Spring Boot多数据源项目中,优先使用如`AbstractRoutingDataSource`实现动态数据源,避免与自动配置冲突[^4]。 通过以上步骤,您的应用应能正常启动。如果问题持续,请提供`pom.xml`依赖列表和启动日志片段以便进一步诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值