如标题名称,其实这篇文章要讲的这个问题跟@Autowired没有太大关系,最终导致该问题的是CGLIB代理,之所以起名该标题,是因为我当时也始终以为该问题是@Autowired注入机制导致的。。。话不多说,直接上代码,情景如下:
在IndexController类中有一段代码:
@RestController
public class IndexController {
@Autowired
private UserService userService;
@RequestMapping("/doSignin")
public String doSignin(SigninCommand signinCommand) {
boolean hasMatch = userService.hasMatchUsername(signinCommand.getUsername());
}
}
在UserServiceImpl类中有一段代码:
@Component
public class UserServiceImpl implements UserService {
@Autowired
private HcUserDao hcUserDao;
@Override
public boolean hasMatchUser(String username, String password) {
int matchCount = hcUserDao.getMatchCount(username, password);
return matchCount > 0;
}
}
在HcUserDao类中有一段代码:
@Repository
public class HcUserDao extends BaseDao {
private final static String MATCHUSERNAME_COUNT_SQL = "SELECT COUNT(*) FROM t_user WHERE username=?";
public final int getMatchUsernameCount(String username) {
return jdbcTemplate.queryForObject(MATCHUSERNAME_COUNT_SQL, new Object[] { username }, Integer.class);
}
}
public class BaseDao {
@Autowired
protected EntityManagerFactory entityManagerFactory;
@Autowired
protected JdbcTemplate jdbcTemplate;
}
然后经过调试,在SpringBoot启动过程中,HcUserDao 中能看到jdbcTemplate对象已经注入成功,而到了UserServiceImpl 中,能看到hcUserDao对象注入成功,但是看jdbcTemplate字段,却是为null。程序调用过程中,也会抛出如下错误:
java.lang.NullPointerException
at org.wongws.hichat.dao.HcUserDao.getmatchUsernameCount(HcUserDao.java:16)
at org.wongws.hichat.service.UserServiceImpl.hasMatchUsername(UserServiceImpl.java:27)
at org.wongws.hichat.controller.IndexController.doSignin(IndexController.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
......
中间经过一大堆波折,最后锁定到如下图的对象中:
看此处会发现hcUserDao是通过CGLIB动态代理生成的,而在target中能看到jdbcTemplate其实是有值的。
OK。既然到这里,问题其实已经转向到CGLIB上了。其实CGLIB在动态代理的时候,是没有对target原样照搬的,属性值会没有设置,这里也就能解释得通为什么jdbcTemplate为null,如果要得到的话,可以通过getJdbcTemplate()方法取值。
至于CGLIB的原理,大家也可以看看其他博文了解下。
这里附上如下文章 如何为spring代理类设置属性值 供参考