qq_61294100 2024-08-18 00:24 采纳率: 76%
浏览 15

spring业务层空指针问题

受Spring管理的service层利用service的引用调用本类方法报空指针异常
1.这是类名

@Service("fileInfoService")
public class FileInfoServiceImpl implements FileInfoService {
    private Logger logger = LoggerFactory.getLogger(FileInfoServiceImpl.class);
    @Resource
    private FileInfoMapper<FileInfo, FileInfoQuery> fileInfoMapper;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private AppConfig appConfig;
    @Lazy
    @Resource
    private FileInfoServiceImpl fileInfoService;

//使用@Lazy注解是由于其中一个方法调用了另一个使用@async注解的异步方法,为了受spring管理,必须使用fileInfoService调用这个
//异步方法,因此产生循环依赖,所以使用@Lazy注解解决循环依赖

2.这是方法名

 @Override
    @Transactional
    public void delFile(String userId, String fileIds) {
        String[] fileIdArray = fileIds.split(",");
        FileInfoQuery fileInfoQuery = new FileInfoQuery();
        fileInfoQuery.setFileIdArray(fileIdArray);
        fileInfoQuery.setUserId(userId);
        fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
        
        List<FileInfo> fileInfoList = fileInfoService.findListByParam(fileInfoQuery);
        if (CollectionUtils.isEmpty(fileInfoList)) {
            return;
        }
        //先删除子目录及文件
        List<String> delFilePidList = new ArrayList<>();
        for (FileInfo fileInfo : fileInfoList) {
       //这里没有报空指针异常
           ** fileInfoService.findAllSubFolderFileIdList(delFilePidList, userId, fileInfo.getFileId(), FileDelFlagEnums.USING.getFlag());**
        }
        if (!CollectionUtils.isEmpty(delFilePidList)) {
            FileInfo updateFileInfo = new FileInfo();
            updateFileInfo.setDelFlag(FileDelFlagEnums.DEL.getFlag());
            this.updateFileDelFlagBatch(updateFileInfo, userId, delFilePidList, null, FileDelFlagEnums.USING.getFlag());
        }
        //再删除自己的文件
        List<String> fileIdList = Arrays.asList(fileIds);
        FileInfo updateFileInfo = new FileInfo();
        updateFileInfo.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
        updateFileInfo.setRecoveryTime(new Date());
        this.updateFileDelFlagBatch(updateFileInfo, userId, null, fileIdList, FileDelFlagEnums.USING.getFlag());

    }




   private void findAllSubFolderFileIdList(List<String> delFilePidList, String userId, String fileId, Integer flag) {
        delFilePidList.add(fileId);
        FileInfoQuery fileInfoQuery = new FileInfoQuery();
        fileInfoQuery.setUserId(userId);
        fileInfoQuery.setFilePid(fileId);
        fileInfoQuery.setDelFlag(flag);
        fileInfoQuery.setFolderType(FileFolderTypeEnums.FOLDER.getType());
        //就是在这里报了空指针异常
        **List<FileInfo> fileInfos = fileInfoService.findListByParam(fileInfoQuery);**
        for (FileInfo fileInfo : fileInfos) {
            findAllSubFolderFileIdList(delFilePidList, userId, fileInfo.getFileId(), flag);
        }
    }

在delFile方法里使用 ** fileInfoService.findAllSubFolderFileIdList**(delFilePidList, userId, fileInfo.getFileId(), FileDelFlagEnums.USING.getFlag());这样的方法调用没有报空指针
但是在findAllSubFolderFileIdList这个方法里面使用List fileInfos = fileInfoService.findListByParam(fileInfoQuery);这样的方式就报了空指针,求解答

  • 写回答

4条回答 默认 最新

  • 何事_ 2024-08-18 00:25
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    这个问题涉及到Java中的多线程和缓存的问题。redisComponentuserInfoService都是从Spring容器中获取的,它们可能会被多个线程同时访问,从而导致数据竞争和空指针异常。

    首先,我们需要检查redisComponent是否已经被正确初始化,并且userInfoService是否已经实现了UserInfoService接口。

    其次,我们可以通过@Async注解来处理异步任务,这样可以确保在主线程执行其他操作之前完成异步任务。

    接下来,我们需要在findAllSubFolderFileIdList方法中添加适当的锁机制,防止多个线程同时修改同一个列表。

    以下是可能的解决方案:

    import java.util.List;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    @Service("fileInfoService")
    public class FileInfoServiceImpl implements FileInfoService {
    
        private final Lock lock = new ReentrantLock();
    
        @Override
        @Transactional
        public void delFile(String userId, String fileIds) {
            String[] fileIdArray = fileIds.split(",");
            FileInfoQuery fileInfoQuery = new FileInfoQuery();
            fileInfoQuery.setFileIdArray(fileIdArray);
            fileInfoQuery.setUserId(userId);
            fileInfoQuery.setDelFlag(FileDelFlagEnums.USING.getFlag());
            
            List<FileInfo> fileInfoList = fileInfoService.findListByParam(fileInfoQuery);
            if (CollectionUtils.isEmpty(fileInfoList)) {
                return;
            }
    
            // 先删除子目录及文件
            List<String> delFilePidList = new ArrayList<>();
            for (FileInfo fileInfo : fileInfoList) {
                // 将此行代码移到try-with-resources语句块内
                lock.lock();
                try {
                    // 这里应该有一个锁机制来防止并发访问
                    // 例如:lock.lockInterruptibly()
                    // 或者使用一个全局的锁对象(如AtomicReference或ConcurrentHashMap)
                    // 但在这个例子中,我们没有看到具体的锁机制实现。
                    // 可能是因为没有足够的上下文信息来确定正确的锁类型。
                    lock.unlock();
                    
                    fileInfoService.findAllSubFolderFileIdList(delFilePidList, userId, fileInfo.getFileId(), FileDelFlagEnums.USING.getFlag());
                } finally {
                    lock.unlock();
                }
            }
    
            // 再删除自己的文件
            List<String> fileIdList = Arrays.asList(fileIds);
            FileInfo updateFileInfo = new FileInfo();
            updateFileInfo.setDelFlag(FileDelFlagEnums.RECYCLE.getFlag());
            updateFileInfo.setRecoveryTime(new Date());
            this.updateFileDelFlagBatch(updateFileInfo, userId, null, fileIdList, FileDelFlagEnums.USING.getFlag());
    
        }
    
    
        private void findAllSubFolderFileIdList(List<String> delFilePidList, String userId, String fileId, Integer flag) {
            delFilePidList.add(fileId);
            FileInfoQuery fileInfoQuery = new FileInfoQuery();
            fileInfoQuery.setUserId(userId);
            fileInfoQuery.setFilePid(fileId);
            fileInfoQuery.setDelFlag(flag);
            fileInfoQuery.setFolderType(FileFolderTypeEnums.FOLDER.getType());
            // 使用try-with-resources语句块内的锁来防止并发访问
            try (Lock lock = this.lock) {
                List<FileInfo> fileInfos = fileInfoService.findListByParam(fileInfoQuery);
                for (FileInfo fileInfo : fileInfos) {
                    // 省略其他逻辑
                }
            } catch (Exception e) {
                // 处理锁冲突的情况
            }
        }
    
        // 在updateFileDelFlagBatch方法中添加锁机制
    }
    

    注意:以上代码仅提供了一个基本的解决方案示例。实际应用中,还需要根据具体情况进行调整,比如添加更多的错误处理、优化性能等。

    评论

报告相同问题?

问题事件

  • 创建了问题 8月18日