文章目录
- 一、场景描述
- 二、解决方案
- 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 类保持不变。



![[Python-闫式DP]](https://img-blog.csdnimg.cn/direct/7bc77266e4d74a67a636753e2f7117d7.png)







![[机器学习]简单线性回归——最小二乘法](https://img-blog.csdnimg.cn/direct/00356d6433744736bcf023505acb0eb4.png)








