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

Spring中DAO继承引发类型转换与Bean重复定义问题求助

问题解决

1. 解决Class cannot be cast to ParameterizedType异常

当创建Test123实例时,this.getClass().getGenericSuperclass()返回的是TestDAO1Impl.class(非泛型的具体类),直接强转ParameterizedType会报错。需要递归向上查找第一个带有泛型参数的父类,也就是直接继承BaseDAOMongoImpl的子类。

修改基类的构造方法和递归逻辑:

public abstract class BaseDAOMongoImpl<K, E extends Entity> implements BaseDAO<K, E> {
    protected Class<E> entityClass;
    protected String entityClassName;
    protected boolean isAuditable;
    private static final Logger LOGGER = LoggerFactory.getLogger(BaseDAOMongoImpl.class);

    public BaseDAOMongoImpl() {
        ParameterizedType pt = (ParameterizedType) getGenericSuperclassWithParameters(this.getClass());
        this.entityClass = (Class<E>) pt.getActualTypeArguments()[1];
        this.entityClassName = this.entityClass.getSimpleName();
        this.isAuditable = this.isAuditableEntity(this.entityClass);
        LOGGER.debug("entity class:{}, isAuditable:{}", this.entityClass, this.isAuditable);
    }

    // 递归查找第一个带泛型参数的父类
    private Type getGenericSuperclassWithParameters(Class<?> source) {
        Type superType = source.getGenericSuperclass();
        // 如果父类是泛型类型,直接返回
        if (superType instanceof ParameterizedType) {
            return superType;
        }
        // 否则继续向上查找父类的父类
        return getGenericSuperclassWithParameters((Class<?>) superType);
    }

    // 省略其他方法...
}

这个方法会自动跳过中间的非泛型子类,找到BaseDAOMongoImpl的直接泛型子类(也就是TestDAO1Impl),从而正确获取泛型参数E。

2. 解决NoUniqueBeanDefinitionException异常

这个异常是因为Test123继承了TestDAO1Impl,且两者都被@Repository标记,导致Spring容器中存在两个TestDAO1Impl类型的Bean(test1DAOImpl和test123)。可以通过以下几种方式解决:

方式一:移除中间类的@Repository注解

如果TestDAO1Impl只是作为父类被继承,不需要单独实例化为Bean,直接去掉它的@Repository注解:

// 去掉@Repository,只保留子类的注解
public class TestDAO1Impl extends BaseDAOMongoImpl<String, Test1MockEvent> {
    public String getOverridingCollectionName() {
        return "test1";
    }
}

@Repository
public class Test123 extends TestDAO1Impl {
    public void testing(){

    }
}

这样容器中只有Test123这一个Bean,不会出现类型冲突。

方式二:使用@Qualifier指定Bean名称

如果需要保留两个Bean,在注入TestDAO1Impl类型的Bean时,用@Qualifier指定具体的Bean名称:

// 注入TestDAO1Impl本身的Bean
@Autowired
@Qualifier("testDAO1Impl") // 默认Bean名称为类名首字母小写
private TestDAO1Impl testDAO1Impl;

// 注入Test123的Bean
@Autowired
@Qualifier("test123")
private TestDAO1Impl test123;

也可以手动给@Repository指定名称:

@Repository("customTestDAO1")
public class TestDAO1Impl extends BaseDAOMongoImpl<String, Test1MockEvent> {
    // ...
}

@Repository("customTest123")
public class Test123 extends TestDAO1Impl {
    // ...
}

然后注入时用对应的名称:@Qualifier("customTestDAO1")。

方式三:用@Primary标记默认Bean

如果希望某一个Bean作为TestDAO1Impl类型的默认实现,给它加上@Primary注解:

@Repository
@Primary // 标记为默认Bean
public class TestDAO1Impl extends BaseDAOMongoImpl<String, Test1MockEvent> {
    // ...
}

@Repository
public class Test123 extends TestDAO1Impl {
    // ...
}

这样当注入TestDAO1Impl类型时,Spring会优先选择带有@Primary的TestDAO1Impl Bean。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 12:59:13