Spring Data接口默认方法重写未生效,仍执行默认实现求助
Spring Data 接口默认方法优先调用,重写实现未生效问题解决
问题场景
定义如下Spring Data接口:
public interface MyInterface<T, H extends Serializable, R extends Serializable> extends Repository<T, ID> { default List<T> findAll(H key) { return Collections.EMPTY_LIST; } }
对应的实现类:
public class RepositoryImpl<T, H extends Serializable, R extends Serializable> extends ACConcreateClassWhichImplementRepository<T, H> implements MyInterface<T, H, R> { @Override public List<T> findAll(H key) { return findSome(hashKey); // 自定义业务方法 } }
异常现象
通过Controller调用findAll方法时,请求命中的是MyInterface中的默认方法,而非RepositoryImpl的重写实现,调用堆栈如下:
java.lang.Thread.State: RUNNABLE at com.MyInterface.findAll(MyInterface.java:12) at java.lang.invoke.LambdaForm$DMH.1294483354.invokeSpecialIFC(LambdaForm$DMH:-1) at java.lang.invoke.LambdaForm$MH.995808242.invoke(LambdaForm$MH:-1) at java.lang.invoke.LambdaForm$MH.1531802663.invoke(LambdaForm$MH:-1) at java.lang.invoke.Invokers$Holder.invokeExact_MT(Invokers$Holder:-1) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:710) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:86) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) at com.sun.proxy.$Proxy167.findAll(Unknown Source:-1)
验证有效场景
若将接口中的findAll改为抽象方法,调用可正常命中RepositoryImpl的实现,堆栈如下:
at com.RepositoryImpl.findAll(RepositoryImpl.java:16) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1) at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289) at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker$$Lambda$1357.2068454901.invoke(Unknown Source:-1) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121) at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:529) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:639) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:163) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) at com.sun.proxy.$Proxy167.findAll(Unknown Source:-1)
使用版本:Spring 5.3.21、Spring Boot 2.7.0
解决方案
方案1:移除接口默认方法实现(最直接)
将MyInterface中的findAll改为抽象方法,沿用已验证有效的方式:
public interface MyInterface<T, H extends Serializable, R extends Serializable> extends Repository<T, ID> { List<T> findAll(H key); // 改为抽象方法 }
方案2:调整AOP拦截器优先级
Spring Data的DefaultMethodInvokingMethodInterceptor会优先处理接口默认方法,导致实现类重写方法被跳过。可通过自定义RepositoryFactoryBean调整拦截器顺序,让实现类方法拦截器先执行:
- 创建自定义RepositoryFactoryBean:
public class CustomRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends RepositoryFactoryBeanSupport<T, S, ID> { public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) { super(repositoryInterface); } @Override protected RepositoryFactorySupport createRepositoryFactory() { return new CustomRepositoryFactory(); } private static class CustomRepositoryFactory extends RepositoryFactorySupport { @Override protected Object getTargetRepository(RepositoryInformation information) { // 返回你的实现类实例,或沿用原有逻辑 return new RepositoryImpl<>(); } @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return RepositoryImpl.class; } @Override protected void configureRepositoryProxy(AopProxyFactory proxyFactory) { super.configureRepositoryProxy(proxyFactory); // 调整拦截器顺序,让实现类方法拦截器优先执行 proxyFactory.addAdvisor(0, new DefaultPointcutAdvisor(new RepositoryMethodInvocationPointcut(), new ImplementationMethodExecutionInterceptor(getRepositoryInformation()))); } } }
- 在接口上指定自定义FactoryBean:
@RepositoryFactoryBean(CustomRepositoryFactoryBean.class) public interface MyInterface<T, H extends Serializable, R extends Serializable> extends Repository<T, ID> { default List<T> findAll(H key) { return Collections.EMPTY_LIST; } }
方案3:使用Repository片段组合
将默认方法与实现类方法拆分为不同片段,确保实现类方法被优先调用:
- 创建包含默认方法的片段接口:
public interface MyDefaultMethods<T, H extends Serializable> { default List<T> findAll(H key) { return Collections.EMPTY_LIST; } }
- 修改主接口继承片段接口:
public interface MyInterface<T, H extends Serializable, R extends Serializable> extends Repository<T, ID>, MyDefaultMethods<T, H> { }
- 实现类保持原有重写逻辑即可。
方案4:升级依赖版本
该问题在Spring Data后续版本中可能已修复,可尝试升级Spring Data Commons到2.7.x最新补丁版,或直接升级Spring Boot到2.7.x系列的最新稳定版本。
内容的提问来源于stack exchange,提问作者SUBHASHC37
相关产品推荐
相关产品推荐

