问题
公司有一个集成开发平台,导入数据库表会自动生成实体类、mapper和xml等文件,这是一件很方便的事,可以省去很多没有技术性的重复工作。
但是最近我在使用这个平台的时候遇到了一个问题,那就是mapper冲突问题。当老表进行导入的时候,会生成与之前项目中已有mapper一样的名字,比如原项目中有个PersonMapper.java的文件,导入后就会有两个PersonMapper.java,这样就会冲突报错,导致项目无法启动。
怎么解决呢?将原先的mapper命名进行修改?显然是不现实的,也违背了开放封闭原则。
原因
首先需要明确,为什么两个一样命名的mapper文件会冲突,因为在在进行对象注入的时候,@Mapper
在生成beanName的时候默认把首字母小写之后返回类名,如果存在两个命名完全一样的文件返回的beanName也是一样的,因此@Resource
会不知道注入哪一个从而冲突。
清楚原因后,要做的就是当注入的时候怎么区分这两个mapper文件,进行不同的注入。
解决
在思考一番后,决定使用@MapperScan
去解决这个问题,核心在于使用其中的nameGenerator
字段。
@MapperScan中的nameGenerator继承于BeanNameGenerator
而在Spring的容器中,是使用BeanNameGenerator去命名检测到的组件,可以通过重写nameGenerator方法去重命名检测到的组件,具体解决代码如下所示:
@Configuration
@MapperScan(
value = {"xxx", "xxx"},
sqlSessionFactoryRef = "sqlSessionFactory",
nameGenerator = ComposerNameGenerator.class
)
public class ComposerNameGenerator implements BeanNameGenerator {
public ComposerNameGenerator() {
}
// definition 是被生成名字的BeanDefinition实例;
// registry是生成名字后注册进的BeanDefinitionRegistry。
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
// 拿到Bean定义信息里面的BeanClassName全类名
// 注意这个不是必须的,因为如果是继承关系,配上父类的依旧行了
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
// 若没有配置本类全类名,去拿到父类的全类名+$child"俩表示自己
if (definition.getParentName() != null) {
generatedBeanName = definition.getParentName() + "$child";
}
// 工厂Bean的 就用方法的名字+"$created"
else if (definition.getFactoryBeanName() != null) {
generatedBeanName = definition.getFactoryBeanName() + "$created";
}
}
// 若一个都没找到,抛错
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither 'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
} else {
return generatedBeanName;
}
}
}
这样配置后,即使是一样命名的mapper文件,只要不在同一个包中依旧可以正常注入。
标签:mapper,definition,重名,全类,nameGenerator,文件,解决,generatedBeanName From: https://www.cnblogs.com/lemondu/p/18589583