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

调用findBySubstring时执行接口默认方法而非实现方法的问题排查

问题:Spring Data Repository默认方法覆盖失效问题

当从ArticleAutocompleteServiceImpl中调用findBySubstring()方法时,执行的是接口的默认方法而非实现类中的实现方法。这是否是泛型导致的?我哪里操作有误?如何保留当前结构并让实现方法生效?

编辑补充:若移除FindBySubstringRepositorySupport中的默认方法仅保留方法签名,功能可正常运行,但缺点是所有实现FindBySubstringRepositorySupport的服务都需添加空实现,而我仅在少数服务中需要真实实现。


ArticleAutocompleteServiceImpl.java

@Service
public class ArticleAutocompleteServiceImpl implements ArticleAutocompleteService {

    private final ArticleRepository articleRepository;

    public ArticleAutocompleteServiceImpl( final ArticleRepository articleRepository ) {
        this.articleRepository = articleRepository;
    }

    @Override
    public List<ArticleURINameDTO> autocomplete( final String q ) {

        // 期望调用实现类的方法,而非接口默认方法
        final List<Article> lst =
            this.articleRepository.findBySubstring( q, 10, ObjectStatus.ENABLED );

        final Locale locale = ...

        return lst.stream().map(a -> new ArticleURINameDTO(a, locale)).toList();
    }
}

ArticleRepositoryImpl.java

public class ArticleRepositoryImpl implements ArticleExtendRepository {

    @PersistenceContext
    private EntityManager entityManager;

    private final StoredProcService storedProcService;

    public ArticleRepositoryImpl( final StoredProcService storedProcService ) {
        this.storedProcService = storedProcService;
    }

    // 本应覆盖接口默认方法的实现
    @Override
    public List<Article> findBySubstring(
        final String       namePart,
        final Integer      limit,
        final ObjectStatus objectStatus
    ) {
        return this.storedProcService.execute( ... );
    }
}

ArticleRepository.java

public interface ArticleRepository extends
    PagingAndSortingRepository<Article, Integer>,
    CrudRepository<Article, Integer>,
    ArticleExtendRepository
{
    // 无额外方法
}

ArticleAutocompleteService.java

public interface ArticleAutocompleteService {

    List<ArticleURINameDTO> autocomplete(String q);

}

FindBySubstringRepositorySupport.java

public interface FindBySubstringRepositorySupport<T> {

    // 无实现时执行的默认方法
    default List<T> findBySubstring(
        final String       namePart,
        final Integer      limit,
        final ObjectStatus objectStatus
    ) {
        throw new IllegalStateException( "方法未实现" );
    }

}

ArticleExtendRepository.java

public interface ArticleExtendRepository extends FindBySubstringRepositorySupport<Article> {

    // 其他无关方法签名
    long countByStatus( ObjectStatus objectStatus );

}

解答

这不是泛型的问题,核心原因是Spring Data Repository的自定义实现类命名规则未被遵守。

Spring Data JPA在生成Repository代理类时,会自动识别对应扩展接口的实现类,但要求实现类的命名必须是「扩展接口名 + Impl」。你的情况中,ArticleExtendRepository是扩展接口,但对应的实现类叫ArticleRepositoryImpl,Spring无法将两者关联,因此会直接调用接口的默认方法,而非你写的自定义实现。

要保留当前结构并解决问题,推荐以下两种方案:

方案一:遵循命名规则重命名实现类

将ArticleRepositoryImpl改名为ArticleExtendRepositoryImpl,使其与扩展接口ArticleExtendRepository的命名匹配。这样Spring Data会自动将该实现类与ArticleExtendRepository关联,ArticleRepository继承该接口后,调用findBySubstring()时就会执行你的自定义实现,而非默认方法。

方案二:手动指定实现类关联

在配置类的@EnableJpaRepositories注解中,通过repositoryImplementationPostfix参数修改默认的实现类后缀(比如你想保留ArticleRepositoryImpl,可以设置repositoryImplementationPostfix = "Impl",同时让ArticleRepositoryImpl直接实现ArticleRepository),但这种方式会破坏当前的接口分层结构,不如方案一规范。

关于你担心的「所有实现FindBySubstringRepositorySupport的服务都要写空实现」的问题,保留默认方法的设计是合理的,只要确保需要自定义实现的扩展接口对应Impl类被Spring正确识别,就不会触发默认方法的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:57:21