程序员子龙(Java面试 + Java学习) 程序员子龙(Java面试 + Java学习)
首页
学习指南
工具
开源项目
技术书籍

程序员子龙

Java 开发从业者
首页
学习指南
工具
开源项目
技术书籍
  • 基础

  • JVM

  • Spring

  • 并发编程

  • Mybatis

  • 网络编程

  • 数据库

  • 缓存

  • 设计模式

  • 分布式

  • 高并发

  • SpringBoot

    • SpringBoot 整合redis
    • SpringBoot 线程池
    • springboot下整合mybatis
    • spring boot 配置文件的加载顺序
    • springboot启动不加载bootstrap.yml文件的问题解决
    • SpringBoot设置动态定时任务
    • springboot整合hibernate
    • ApplicationRunner、InitializingBean、@PostConstruct使用详解
    • Spring Boot 优雅的参数校验方案
    • ELK处理 SpringBoot 日志,太优雅了!
    • SpringBoot配置数据源
    • Spring Boot 默认数据库连接池 —— HikariCP
    • 数据库连接池Hikari监控
    • Spring Boot中使用AOP统一处理Web请求日志
    • SpringBoot 三大开发工具,你都用过么?
    • Spring Boot 3.2 + CRaC = 王炸!
    • springboot启动的时候排除加载某些bean
    • spring boot中集成swagger
    • springboot项目引入这个包以后把原来的json报文改为了xml格式返回
    • SpringBoot中new对象不能自动注入对象和属性的问题
    • 使用 Spring Boot Actuator 监控应用
    • 记录一次springboot自动任务线上突然不执行问题排查过程
    • SpringBoot定时任务@Scheduled源码解析
    • Spring Boot + Lua = 王炸!
    • Spring Boot 实现定时任务动态管理
    • SpringBoot的@Async注解有什么坑?
    • druid 参数配置详解
    • Spring Boot HandlerMethodArgumentResolver 使用和场景
    • SpringBoot数据加解密
    • 解决controller层注入的service为null
      • 问题描述
      • 问题排查
      • 原因
      • 问题复现
      • 问题分析
      • 其他原因
    • 在 Spring Boot 中通过 RequestBodyAdvice 统一解码请求体
    • SpringBoot之使用Redisson实现分布式锁(含完整例子)
  • SpringCloudAlibaba

  • Nginx

  • 面试

  • 生产问题

  • 系统设计

  • 消息中间件

  • Java
  • SpringBoot
程序员子龙
2024-08-07
目录

解决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();
    }
}

1
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();
    }
}

1
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();
    }
}

1
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 {
      
    }
1
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("/**");
  }
}
1
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);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上次更新: 2024/08/12, 14:38:19
SpringBoot数据加解密
在 Spring Boot 中通过 RequestBodyAdvice 统一解码请求体

← SpringBoot数据加解密 在 Spring Boot 中通过 RequestBodyAdvice 统一解码请求体→

最近更新
01
一个注解,优雅的实现接口幂等性
11-17
02
MySQL事务(超详细!!!)
10-14
03
阿里二面:Kafka中如何保证消息的顺序性?这周被问到两次了
10-09
更多文章>
Theme by Vdoing | Copyright © 2024-2024

    辽ICP备2023001503号-2

  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式