为所有MongoRepository添加通用方法失败,启动报错求解决
你遇到的核心问题是自定义Repository工厂类中返回了接口作为基础实现类,Spring Data尝试实例化接口时找不到构造方法,从而抛出异常。下面一步步拆解问题并给出修复:
1. 错误根源:getRepositoryBaseClass返回了接口而非实现类
在你的BaseRepositoryFactory中,这段代码是问题所在:
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return BaseRepository.class; // 返回的是接口! }
Spring Data需要的是具体的实现类来创建实例,而不是接口。你应该返回BaseRepositoryImpl.class——它是BaseRepository接口的实际实现。
2. 修复BaseRepositoryFactory的两个关键方法
首先修正getRepositoryBaseClass,同时简化getTargetRepository方法(不用手动创建MappingMongoEntityInformation,利用父类的方法更可靠):
private static class BaseRepositoryFactory<T, ID extends Serializable> extends MongoRepositoryFactory { private final MongoOperations mongo; public BaseRepositoryFactory(MongoOperations mongoOperations) { super(mongoOperations); this.mongo = mongoOperations; } @SuppressWarnings("unchecked") @Override protected Object getTargetRepository(RepositoryMetadata metadata) { // 利用父类方法获取MongoEntityInformation,避免手动创建的错误 MongoEntityInformation<T, ID> entityInformation = getEntityInformation((Class<T>) metadata.getDomainType()); return new BaseRepositoryImpl<>(entityInformation, mongo); } @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { // 返回实际的实现类,而非接口 return BaseRepositoryImpl.class; } }
3. 补全BaseRepositoryImpl的字段初始化
你的BaseRepositoryImpl中声明了mongoOperations和metadata字段,但构造函数里没有给它们赋值,这会导致mySearch方法调用时出现空指针异常。修正构造函数:
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> implements BaseRepository<T, ID> { private final MongoOperations mongoOperations; private final MongoEntityInformation<T, ID> metadata; public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) { super(metadata, mongoOperations); // 初始化字段 this.metadata = metadata; this.mongoOperations = mongoOperations; } @Override public Page<T> mySearch(Query query, Pageable pageable) { long total = mongoOperations.count(query, metadata.getJavaType()); List<T> content = mongoOperations.find(query.with(pageable), metadata.getJavaType()); return new PageImpl<>(content, pageable, total); } }
4. 简化Repository接口的继承关系
你的ClientsRepository继承关系是对的,但可以简化为直接继承BaseRepository(因为BaseRepository已经继承了MongoRepository):
public interface ClientsRepository extends BaseRepository<Client, String> { }
为什么之前的代码会报错?
当你返回BaseRepository.class作为基础类时,Spring Data会尝试通过反射创建这个接口的实例,但接口本身没有构造方法,自然找不到匹配MappingMongoEntityInformation和MongoTemplate参数的构造函数,就抛出了你看到的异常。
完成以上修改后,你的自定义通用方法应该就能正常工作了。
内容的提问来源于stack exchange,提问作者Defenestrate

