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

