今天在搭建 SpringBoot+SpringMVC+mybaits 项目的时候,遇到了一个奇怪的问题。
Controller 中需要注入 Service,Service 中需要注入 Mybatis 的 Dao 接口,属性都是通过“@+ 标签名”的方式注入的。比如一个简单的查询用户的 controller,需要注入一个与用户有关的 service:
@RequestMapping("/user")
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/list/all")
public List<User> listAll(){return userService.listAll();
}
}
service 中又要注入 Dao 的接口:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public List<User> listAll(){return userMapper.selectAll();
}
}
但是在 Service 层竟然出现了如此问题:
不过问题不大,项目能够正常运行,并且使用 @Resource 标签代替 @Autowired 就可以完全解决问题:
但是为什么 @Autowired 在 IDEA 里面会有问题呢,经过网上寻找 + 个人思考,有以下两点结论:
- 根据使用报错信息在网上搜索出的解决方案的总结
首先是 IDEA 这个工具强大的检测报警机制,如果 IDEA 说你的代码没问题,那么它肯定能编译通过。给你报错,就算不影响项目运行,那也确实有些不合适的地方。看到网上有些答案很可笑,让你去 settings 里面把这个报警关掉,这不是掩耳盗铃吗?当然了,如果不影响项目的正常运行,关掉报警也是一种方法,毕竟程序员看不见 warning。但是如果项目无法运行,仅关掉报警根本没卵用。
- @Autowired 与 @Resource 的区别
@Autowired 根据 type 注入,@Resource 根据 name 注入,本质上均实现了注入效果,只是依据不同,那么为什么我在 Controller 中使用 @Autowired 就没问题呢,我认为原因在于两个地方注入 Bean 的类型不一样。以下是个人思考,如有不对请指教。
一般来说,注入 controller 的 service 虽然一般来说我们都是注入一个接口,但是该接口有实现类,并且使用 @Service 进行关联,所以注入类型应该也可以视为一个类,但是 mybatis 仅需提供 Dao 接口,也就是说,注入 service 的 dao 只是一个接口,而没有实现类,虽然 mybatis 能够通过 Dao 接口和 xml 文件实现与数据库的操作,但是 @Autowired 并没有这个识别功能,可能它就认为你类型不匹配,无法使用通过类型注入的方法。这个理论我通过一个简单的方法验证通过,做法如下:
我把 service 的实现类给取消了实现接口的语句‘implements UserService’,然后变成下面这样:
@Service
public class UserServiceImpl{
@Resource
private UserMapper userMapper;
public List<User> listAll(){return userMapper.selectAll();
}
}
此时,IDEA 给 controller 中的注入也报出同样的警告:
所以我有充足的理由断定,应该是这个原因,也就是说,@Autowired 不适用 service 层对于 dao 的注入。