在 Spring 中,@Repository
注解实现异常转换主要通过以下方式:
一、原理
-
代理机制
- 当一个类被标注为
@Repository
后,Spring 会为这个类创建一个代理对象。这个代理对象会拦截对该类方法的调用。 - 当被代理的方法抛出特定的数据库相关异常时,代理对象会捕获这些异常,并将其转换为 Spring 统一的异常体系中的异常。
- 当一个类被标注为
-
异常翻译器(PersistenceExceptionTranslationPostProcessor)
- Spring 框架中有一个名为
PersistenceExceptionTranslationPostProcessor
的后置处理器。这个后置处理器会在 Spring 容器初始化时扫描所有被标注为@Repository
的组件,并为它们安装异常翻译器。 - 异常翻译器会根据抛出的异常类型进行判断,如果是数据库特定的异常,就会将其转换为 Spring 的
DataAccessException
体系中的异常。
- Spring 框架中有一个名为
二、具体过程
-
数据库操作抛出异常
- 当在数据访问层进行数据库操作时,如果出现问题,数据库驱动或数据库访问框架会抛出特定的数据库异常,比如 JDBC 中的
SQLException
或者 JPA/Hibernate 中的特定异常。
- 当在数据访问层进行数据库操作时,如果出现问题,数据库驱动或数据库访问框架会抛出特定的数据库异常,比如 JDBC 中的
-
异常捕获和转换
- 被
@Repository
标注的组件的代理对象会捕获这些异常。 - 代理对象会根据异常类型,使用异常翻译器将数据库特定异常转换为 Spring 的
DataAccessException
体系中的异常。例如,将SQLException
转换为DataAccessException
的子类InvalidDataAccessResourceUsageException
等。
- 被
-
异常传播
- 转换后的异常会被抛给调用者,通常是业务逻辑层或控制层。
三、代码示例
假设我们有一个数据访问层的方法:
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositoryImpl {
public void someDatabaseOperation() {
// 假设这里进行数据库操作时出现问题,抛出了 SQLException
throw new java.sql.SQLException("Database error");
}
}
在业务逻辑层调用这个方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepositoryImpl userRepository;
public void performBusinessLogic() {
try {
userRepository.someDatabaseOperation();
} catch (Exception e) {
// 这里捕获到的是经过转换后的 Spring 的 DataAccessException 体系中的异常
System.out.println("Caught data access exception: " + e.getMessage());
}
}
}
在这个例子中,当someDatabaseOperation
方法抛出SQLException
时,由于UserRepositoryImpl
被标注为@Repository
,这个异常会被转换为 Spring 的DataAccessException
体系中的异常,并在业务逻辑层被捕获和处理。
这样做的好处是,使得应用的异常处理更加统一和方便,业务逻辑层不需要了解具体的数据库异常类型,只需要处理 Spring 统一的DataAccessException
体系中的异常即可。