今天在使用 IDEA 使用 MyBatis 的时候遇到了这种情况:

已解决:IDEA中@Autowired自动注入MyBatis Mapper报红警告的几种解决方法_构造方法

 

可以看到 userMapper 下有个红色的波浪警告,虽然代码没有任何问题,能正常运行,但是这个红色警告在这里杵着确实让人很窝心。

于是我在网上找了找,最终明白了原因所在:

  • 因为 IDEA 可以智能的理解上下文,然而 UserMapper 这个接口是 MyBatis 的 IDEA 理解不了。
  • 而​​@Autowired​​​  注解,默认情况下要求依赖对象(也就是​​userMapper​​ )必须存在。而 IDEA 认为这个对象的实例/代理是个 null ,所以就友好地给个提示。

 

然后最终的解决方案总结了几个,按需使用把:

 

方法1:为  ​​@Autowired​​  注解设置 required = false

使用 ​​@Autowired​​ 注解时,若希望允许 null 值,可设置 required = false,像这样:

1 @Autowired(required = false)
2 private UserMapper userMapper;

这样就不会有警告了。原因很好理解:IDEA  认为 userMapper 是个 null ,给了警告;加上 required = false 后,使用  ​​@Autowired​​  注解不再去校验 userMapper 是否存在了。也就不会有警告了。

总结:

这种方式有点蛋疼。一个庞大的既有项目,可能到处都在引用 Mapper,总不能到处都补上 required = false 吧……而且对于新手/新员工,很难一眼看懂加 required = false 属性只是为了解决 IDEA 的警告。

 

方法2:使用 @Resource 替换 @Autowired

像这样:

@Resource
private UserMapper userMapper;

这样也不会再有讨厌的警告。如果你对原因感兴趣,不妨了解一下《@Autowired 与@Resource的区别》。

总结:

这种方式挺赞,但如果一个项目已经大量使用 @Autowired ,然后为了个警告到处改成 @Resource ,也有点蛋疼。

 

方法3:在 Mapper 接口上添加 @Repository 注解

@Repository
public interface UserMapper extends Mapper {

}

这样能让你的

@Autowired
private UserMapper userMapper;

不再报红。

当然,如果你用 @Component 替换 @Repository 也是可以的。原理大致:IDEA 不是认为  ​​userMapper​​ 是个 null 嘛…加个 @Repository 注解骗一下 IDEA 就OK了……

总结:

这种方式比较赞,改动小,也简单,我比较喜欢。

 

方法4:用 Lombok

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestService {

private final UserMapper userMapper;
...

}

但如果自己手写成 Lombok 生成的代码,IDEA依然会给你报警告 。我猜,应该是 IDEA 的 Lombok 插件把 IDEA 搞懵逼了…所以不提示了…

总结 :这是我目前最喜欢的方式。原因有2:

  • Spring 官方并不建议直接在类的 field 上使用 @Autowired 注解,原因详见:​​《Why field injection is evil》​​ ,用本方法可将 field 注入编程构造方法注入,Spring 是比较推荐的。
  • 体现了 Lombok 的优势,简化了你的代码。而且你也不用在每个 field 上都加上 @Autowired 注解了。

不过这种方式也有缺点:那就是如果你类之间的依赖关系比较复杂,特别是存在循环依赖(A引用B,B引用A,或者间接的循环引用)时,应用将会启动不起来……这其实是构造方法注入方式的缺点。

 

方法5:把 IDEA 的警告关掉。

个人没试过,也没有动力去试。没有提示的 IDEA 是没有灵魂的,我从来不去修改 IDEA 的任何警告设置。

 

方法6:安装 mybatis plugin 即可解决该问题。

 

总结:

以上是解决问题的6种方法。问题本身其实比较简单,但其实隐藏的知识点其实挺多的,例如:

  • @Autowired 和 @Resource 有什么区别。
  • 为什么 Spring 不建议使用 field 方式注入。
  • @Repository、@Componnt、@Controller、@Service 有什么区别。