说明:在使用@Autowired注解,自动装配某Bean时,为了避免循环依赖(即自己注入自己,或两个Bean之间互相注入),可使用@Lazy注解,使其不在项目启动的时候就注入Bean,而是在首次使用的时候再注入,即懒加载,可以解决循环依赖的问题。
本文介绍使用@Lazy可能会出现的空指针异常(NPE)。
场景
如下,在 AsyncServiceImpl 内调用本类的方法,自己注入了自己
java
import com.hezy.mapper.UserMapper;
import com.hezy.pojo.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class AsyncServiceImpl {
@Autowired
@Lazy
private AsyncServiceImpl asyncService;
@Autowired
private UserMapper userMapper;
public void insertDTO1(UserDTO userDTO) {
asyncService.insert(userDTO);
}
private void insert(UserDTO userDTO) {
userMapper.insertUser(userDTO);
}
}
这种情况,如果不加 @Lazy 注解,启动项目,会报循环依赖错误
问题
启动项目,发现在这里发生了空指针异常
解决
排查下来是因为成员方法insert()为private修饰,换成public就行了,如下:
分析
推测可能与动态代理的方式有关,CGLIB动态代理要求被代理的类或方法不能被final修饰。
对于上述场景,除了修改成员方法的修饰符,把private改为public,还可以考虑不走代理,而直接调用成员方法,如下,都不需要注入自己。
java
@Autowired
private UserMapper userMapper;
public void insertDTO1(UserDTO userDTO) {
insert(userDTO);
}
public void insert(UserDTO userDTO) {
userMapper.insertUser(userDTO);
}
大家可能有两个问题:
问:为什么要自己注入自己?直接调用成员方法不就行了?
答:因为要考虑到事务,如果用声明式注解,直接调用成员方法,事务会失效。上述代码没有事务问题,故可以直接调用成员方法。
问:为什么方法要用private修饰?直接用public多省事。
答:因为规范,成员方法如果只在本类中使用,须用private修饰。