SpringBoot项目中添加了@Service然而无法注入Service接口的问题

前言

昨天在项目中使用代码生成器生成了各层面的代码,但是由于未知的原因一直无法调用。经过多方查找后才发现是@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有关的类和接口甚至文件开始。

  1.  检查xml文件所在package名称是否和Mapper interface所在的包名一一对应;
  2.  检查xml的namespace是否和xml文件的package名称一一对应;
  3.  检查方法名称是否对应;
  4.  检查配置文件里的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注解的共存情况问题,现在把结果附加上去。

  1. 只使用@Mapper注解,不使用@MapperScan注解。会扫描@Mapper注解所在接口,生成动态代理类,注入到Spring容器中。
  2. 只使用@MapperScan注解,不使用@Mapper注解。会扫描@MapperScan注解配置的包下面的接口生成动态代理类,注入到Spring容器中。
  3. @Mapper、@MapperScan注解都使用,使用@Mapper的接口,如果在@MapperScan注解中有配置包路径,那么可以正常使用。
  4. @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源码,一边看,一边自己尝试去实现,结果掉在坑了,研究了近一周才爬出来,特地来这博客园记录下来,一...icon-default.png?t=N7T8https://www.jianshu.com/p/b72a1ffb3672

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值