文章目录
- 一、场景描述
- 二、解决方案
- 1. 使用 `@Lazy`(推荐)
- 2. 使用方法注入
- 3. 使用 `ApplicationContext`
- 4. 分离服务层
- 5. AspectJ 代理模式
在 Spring Boot
开发中,我们时常遇到需要在一个类的内部调用自己的其他方法,并且这些方法可能需要事务支持。这种场景通常发生在业务逻辑较为复杂的服务类中,其中一些操作需要确保数据的一致性和完整性。本文将以 MediaFileServiceImpl
类为例,探讨如何在 Spring Boot
中有效地使用当前类的代理类来处理内部事务。
一、场景描述
考虑一个典型的例子:在 MediaFileServiceImpl
服务类中,upload
方法需要调用 upload2Mysql
方法。这里,upload2Mysql
方法是事务性的,意味着它涉及到数据库操作,这些操作需要在一个事务中被处理。如果直接在 upload
方法中调用 upload2Mysql
,由于 Spring
的代理方式,事务管理可能不会被正确应用,因为实际上是在同一个实例内部进行方法调用,绕过了 Spring
的代理。
@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {
@Lazy
@Autowired
private MediaFileService mediaFileService;
@Override
public UploadFileResultDto upload() {
// ... 一些业务逻辑 ...
mediaFileService.upload2Mysql();
// ... 其他业务逻辑 ...
}
@Transactional
@Override
public MediaFiles upload2Mysql() {
// ... 事务性操作 ...
}
}
二、解决方案
1. 使用 @Lazy
(推荐)
在 MediaFileServiceImpl
类中使用 @Lazy
注解解决循环依赖问题。
@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {
@Lazy
@Autowired
private MediaFileService mediaFileService;
@Override
public UploadFileResultDto upload() {
// ... 一些业务逻辑 ...
mediaFileService.upload2Mysql();
// ... 其他业务逻辑 ...
}
@Transactional
@Override
public MediaFiles upload2Mysql() {
// ... 事务性操作 ...
}
}
2. 使用方法注入
方法注入是一种允许在运行时动态注入方法实现的技术。这里,我们通过一个简单的例子来说明如何应用方法注入。
@Service
@Slf4j
public abstract class MediaFileServiceImpl implements MediaFileService {
@Override
public UploadFileResultDto upload() {
// ... 一些业务逻辑 ...
getMediaFileService().upload2Mysql();
// ... 其他业务逻辑 ...
}
@Transactional
@Override
public MediaFiles upload2Mysql() {
// ... 事务性操作 ...
}
@Lookup
protected abstract MediaFileService getMediaFileService();
}
3. 使用 ApplicationContext
这种方法通过 ApplicationContext
获取当前类的代理。
@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {
@Autowired
private ApplicationContext context;
private MediaFileService getMediaFileService() {
return context.getBean(MediaFileService.class);
}
@Override
public UploadFileResultDto upload() {
// ... 一些业务逻辑 ...
getMediaFileService().upload2Mysql();
// ... 其他业务逻辑 ...
}
@Transactional
@Override
public MediaFiles upload2Mysql() {
// ... 事务性操作 ...
}
}
4. 分离服务层
将事务性方法移至另一个服务类中。
@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {
@Autowired
private MediaFileTransactionalService transactionalService;
@Override
public UploadFileResultDto upload() {
// ... 一些业务逻辑 ...
transactionalService.upload2Mysql();
// ... 其他业务逻辑 ...
}
}
@Service
@Transactional
class MediaFileTransactionalService {
public MediaFiles upload2Mysql() {
// ... 事务性操作 ...
}
}
5. AspectJ 代理模式
使用 AspectJ 代理模式而不是默认的 JDK 动态代理。
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Configuration
public class AppConfig {
// ... 其他配置 ...
}
然后,您的 MediaFileServiceImpl
类保持不变。