昨天在项目中使用代码生成器生成了各层面的代码,但是由于未知的原因一直无法调用。经过多方查找后才发现是@MapperScan注解的问题,由于这个藏得比较隐蔽,所以在此记录一下。
在接口完成后调用接口,发现无法调用接口,显示错误是
ERROR 1552 --- [nio-8081-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.mydemo.service.xxxxxx] with root cause
大致的意思是绑定错误,无法达到映射的意思。无法找到Service包下面的xxxxService实现类。
从百度上看,一般可能是mapper绑定失败所致,所以先从排查mapper有关的类和接口甚至文件开始。
但是这里排查了很多遍,都没有发现相关的问题。同事给了我一个方法,测试接口是否确实被注入了。
@Autowired private ApplicationContext applicationContext; @GetMapping("test") public void test(){ String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { Object bean = applicationContext.getBean(beanName); if (bean instanceof Mapper) { // 处理Mapper的Bean实例 System.out.println(beanName + " is a Mapper bean."); } } }
运行后发现,mapper确实注入了。
所以有可能是Service接口和实现类的问题,按照这个思路进行排查。
然后排查到启动类上面,当时的启动类是这么写的
@MapperScan(value = { "com.jsb.iot.common", "com.jsb.iot.stopcar.parking_lot", "com.jsb.iot.stopcar.order" }) @SpringBootApplication public class StopCarApplication { public static void main(String[] args) { SpringApplication.run(StopCarApplication.class, args); } }
试着给类名后面的包名加上dao以缩小扫描范围。
@MapperScan(value = { "com.jsb.iot.common", "com.jsb.iot.stopcar.parking_lot.dao", "com.jsb.iot.stopcar.order.dao" }) @SpringBootApplication public class StopCarApplication { public static void main(String[] args) { SpringApplication.run(StopCarApplication.class, args); } }
发送请求测试,结果测试成功。搜查后发现原因
@Mapper
org.apache.ibatis.annotations.Mapper;
作用:给该注解下面的接口在编译时生成对应的动态代理类并且注入到Spring容器中。
@MapperScan
org.mybatis.spring.annotation.MapperScan;
作用:在启动类上配置,配置的是持久层接口的包的路径。编译后会把路径下所有的接口都生成动态代理类
包下面的所有接口都会实现代理类,这就意味着在之前的写法中,除了impl类被注入了Spring容器中之外,还注入了一个Service的实现类,于是乎在Controller层调用Service时,并没有真正获取被注入的impl类,所以无法调用mapper接口。这种情况只有运行时才会报错。
@MapperScan指定范围下的所有接口,是所有接口,不论是Mapper接口、还是Service接口、或者是其它什么接口,只要接口是在@MapperScan指定的范围内,Mybatis都会对该接口进行对应的代理实现(并将代理实现类注册进容器中)。所以在使用@MapperScan时,一定要注意指定的范围不能过大。
在排查问题时,偶然遇到@Mapper和@MapperScan注解的共存情况问题,现在把结果附加上去。
- 只使用@Mapper注解,不使用@MapperScan注解。会扫描@Mapper注解所在接口,生成动态代理类,注入到Spring容器中。
- 只使用@MapperScan注解,不使用@Mapper注解。会扫描@MapperScan注解配置的包下面的接口生成动态代理类,注入到Spring容器中。
- @Mapper、@MapperScan注解都使用,使用@Mapper的接口,如果在@MapperScan注解中有配置包路径,那么可以正常使用。
- @Mapper、@MapperScan注解都使用,使用@Mapper的接口,如果在@MapperScan注解中没有配置包路径,那么会报错,解决办法,就是在@MapperScan注解中配置正确路径下的包即可。
2021120101_@Mapper和@MapperScan注解以及共存_mapperscan和mapper注解-CSDN博客目录1、@Mapper、@MapperScan注解2、报错使用场景1、@Mapper、@MapperScan注解@Mapper注解:使用:直接在接口类上使用,包是:org.apache.ibatis.annotations.Mapper作用:为有此注解的接口生成动态代理类,并且注入到spring容器中。@MapperScan注解:使用:在启动类上配置,配置的是持久层接口的包路径,标注批量生成此包下的接口的动态代理类,并且注入到容器中。2、报错使用场景问题描述:使用_mapperscan和mapper注解https://blog.csdn.net/m0_48983233/article/details/121648122
@MapperScan与@Mapper_@mapperscan和@mapper-CSDN博客@MapperScan与@Mapper@MapperScan与@Mapper背景说明@MapperScan与@Mapper的作用通过@Mapper让Mybatis对接口提供代理实现通过@MapperScan让Mybatis对接口提供代理实现背景说明我们在编写mapper时,只需要编写接口而不需要对其实现,由Mybatis框架对接口提供对应的代理实现类(,并将代理实现类注册进容器中)。但是Mybatis是怎么知道需要对哪些接口进行代理实现呢,就是通过@MapperScan与@Mappe_@mapperscan和@mapperhttps://blog.csdn.net/justry_deng/article/details/124227444
SpringBoot中Service实现类添加@Service却任然无法注入的问题 - 简书最近一直在研究Spring Boot。从GitHub上下载了一个my-Blog源码,一边看,一边自己尝试去实现,结果掉在坑了,研究了近一周才爬出来,特地来这博客园记录下来,一...https://www.jianshu.com/p/b72a1ffb3672
上一篇:SpringBoot-项目部署