解决controller层注入的service为null
# 问题描述
的接口没有测试就给到了前端,前端在调用后接口出现NullPointerException
空指针异常:
# 问题排查
根据详细的错误日志发现,代码中通道@Autowired注解注入的Service类对象为NULL。 有人可能会说会不会是Service层的实现类上忘记加了@Service注解,显然不是。如果Service层的实现类没有加@Service注解,而又在Controller层进行注入,程序在启动时就会报错,以下是报错信息:
# 原因
后来经过筛查以及和其他Controller层的类进行对比差异,发现接口方法的修饰符是private
,而且只有这一个方法是被private
修饰的。于是我将其改为public
,最后进行测试,不会报错了。
错误代码
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getUserName")
private String getUserName() {
return userService.getUserName();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
正确代码
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getUserName")
public String getUserName() {
return userService.getUserName();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 问题复现
新建一个项目
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getUserName")
private String getUserName() {
return userService.getUserName();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
私有方法,service也可以注入成功。再回到之前的项目上,发现有AOP日志切面,难道是这个有关?把切面去掉,私有的接口方法确实也成功。
@Pointcut("execution(* com.demo.controller.*.*(..))")
public void webLog() {}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
}
2
3
4
5
6
7
# 问题分析
我们这里使用的是CGLIB代理,该代理的原理是:
动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
既然CGLIB是通过生成子类的方式来创建代理,那么它生成的子类肯定就要继承父类。
关于Java中的继承,有一条很重要的特性就是:
子类拥有父类非 private 的属性、方法。那么也就是说如果父类中有private方法,生成的代理类中是看不到的。
换言之,由CGLIB创建的代理类,不会包含父类中的私有方法。另外由于CGLIB代理类的生成过程,决定了其成员(无论是private还是protected)均是null。
# 其他原因
1、该类没有托管给Spring 管理
一般在类的上面添加@Component就可以了
2、看你的xxxxxApplication是否在根目录,因为Springboot默认扫描的就是启动类下的目录,当然也可以通过过@ComponenScan注解去指定扫描范围
3、通过new 的方式创建出来的实例是没有交给Spring 进行管理的,没有被Spring 管理的实例,sSpring ring是无法自动注入bean的,所以为null
例如:
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SessionInterceptor()).excludePathPatterns("/static/**").addPathPatterns("/**");
}
}
2
3
4
5
6
7
8
public class SessionInterceptor implements HandlerInterceptor {
@Autowired
private IUserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
HttpSession session = httpServletRequest.getSession();
String username = (String)session.getAttribute("userName");
//运行时候userService是null
SysUser userInfo =userService.getUserInfoByUserName(username).get(0);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16