You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中调用SongRepo方法时this.songRepo为何为null?

问题描述

我需要实现服务层查询PostgreSQL数据库所有歌曲的功能,已在服务层实现SongServiceInterface接口,但在main方法实例化SongService调用方法,或通过/songs端点发送HTTP请求时,均抛出空指针异常:

Caused by: java.lang.NullPointerException: Cannot invoke "com.techm.react.Wasteland.repository.SongRepo.findAll()" because "this.songRepo" is null.

注意:应用启动时可正常将对象持久化到数据库,但调用repo/service内的方法会触发空字段错误。


实体类(Model)

package com.techm.react.Wasteland.models;

import lombok.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import javax.persistence.*;
import java.sql.Time;

@Entity
@Table(name = "song")
@NoArgsConstructor
@AllArgsConstructor
@Getter @Setter
@EqualsAndHashCode
@ToString
public class Song {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "title")
    private String title;

    @JoinColumn(name = "album")
    @ManyToOne
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Album album;

    @Column(name = "artists")
    private String artists;

    @Column(name = "track")
    private int track;

    @Column(name = "track_length")
    private Time length;
}

数据传输对象(DTO)

package com.techm.react.Wasteland.dto;

import com.techm.react.Wasteland.models.Album;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Time;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SongDTO {

    private String title;
    private AlbumDTO album;
    private String artists;
    private int track;
    private Time length;
}

仓库接口(Repo)

package com.techm.react.Wasteland.repository;

import com.techm.react.Wasteland.models.Song;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
@Repository
public interface SongRepo extends JpaRepository<Song, Integer> {

    public abstract List<Song> findAll();

    public abstract List<Song> findByArtist();

    public abstract Song findByTrack();
}

服务类(Service)

package com.techm.react.Wasteland.service;

import com.techm.react.Wasteland.dto.SongDTO;
import com.techm.react.Wasteland.models.Song;
import com.techm.react.Wasteland.repository.SongRepo;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service @Configurable
public class SongService implements SongServiceInterface{
    @Autowired
    SongRepo songRepo;

    @Autowired
    private ModelMapper modelMapper;

    public List<SongDTO> findAllSongs() {

        List<SongDTO> songDTOS = new ArrayList<>();

        List<Song> songs = songRepo.findAll();
        for(Song s: songs) {
            songDTOS.add(modelMapper.map(s, SongDTO.class));
        }

        return songDTOS;
    }

    public SongDTO getSongByTitle(String title) throws NoSuchFieldException {
        SongDTO song = new SongDTO();
        if(title == song.getTitle()){
            return song;
        }
        else throw new NoSuchFieldException("The song by that title does not exist");
    }

    public SongDTO findByTrack(int track) {
        SongDTO song = new SongDTO();
        if(song.getTrack() == track) {
            return song;
        }
        return null;
    }
}

主启动类(Main)

package com.techm.react.Wasteland;

import com.techm.react.Wasteland.controller.AlbumController;
import com.techm.react.Wasteland.controller.SongController;
import com.techm.react.Wasteland.service.SongService;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@ComponentScan({"com.server", "com.server.config"})
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class WastelandApplication {

    @Bean
    public ModelMapper modelMapper() {
        ModelMapper modelMapper = new ModelMapper();
        return modelMapper;
    }

    public static void main(String[] args) {
        SpringApplication.run(WastelandApplication.class, args);

        SongService songService = new SongService();
        System.out.println(songService.findAllSongs());
    }
}

解决方案

问题根源

  1. 手动实例化服务类导致依赖注入失效:main方法中用new SongService()创建对象,该对象不属于Spring容器管理,Spring无法自动注入SongRepo和ModelMapper,导致songRepo为null。
  2. 组件扫描路径错误:@ComponentScan指定的{"com.server", "com.server.config"}未覆盖代码实际包路径com.techm.react.Wasteland,Spring无法扫描到Repo、Service等组件,这些Bean无法被容器管理。
  3. 错误排除数据源自动配置:@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})禁用了Spring Boot的数据源自动配置,会导致JPA相关组件初始化异常,间接影响Repo注入。

修复步骤

  1. 修正组件扫描路径:
    移除自定义@ComponentScan(@SpringBootApplication默认扫描主类所在包及其子包,足够覆盖所有组件);若需保留,需补充实际包路径:

    @ComponentScan({"com.techm.react.Wasteland", "com.server", "com.server.config"})
    
  2. 恢复数据源自动配置:
    删除@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}),确保Spring Boot自动配置数据源和JPA组件,让SongRepo正常被容器创建并注入。

  3. 从Spring容器获取服务实例:
    main方法中不要手动new对象,通过应用上下文获取Bean:

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(WastelandApplication.class, args);
        SongService songService = context.getBean(SongService.class);
        System.out.println(songService.findAllSongs());
    }
    
  4. 优化仓库接口:
    JpaRepository已自带findAll()方法,无需重复声明;同时修正参数缺失的查询方法,符合Spring Data JPA命名规范:

    public interface SongRepo extends JpaRepository<Song, Integer> {
        List<Song> findByArtists(String artists);
        Song findByTrack(int track);
        Song findByTitle(String title);
    }
    
  5. 修复服务类业务逻辑:
    修正getSongByTitle和findByTrack的错误逻辑,改为调用Repo查询数据库:

    public SongDTO getSongByTitle(String title) throws NoSuchFieldException {
        Song song = songRepo.findByTitle(title);
        if(song != null){
            return modelMapper.map(song, SongDTO.class);
        }
        throw new NoSuchFieldException("The song by that title does not exist");
    }
    
    public SongDTO findByTrack(int track) {
        Song song = songRepo.findByTrack(track);
        return song != null ? modelMapper.map(song, SongDTO.class) : null;
    }
    

内容的提问来源于stack exchange,提问作者Shayne McPherson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:39:17