简介
本文介绍Spring的IOC常见的问题。
注入为null
使用@Autowired注入bean的时候,有时注入失败,bean为null,主要有以下几种原因:
- 注入的类没有加入容器。比如:没加@Component,没被加入到SpringBoot包扫描路径
- 在特殊bean中注入:Filter、Listener
- 不在一个上下文中
- 静态方法使用静态注入的变量
特殊bean中注入
原因
因为Filter和Listener加载顺序优先于普通bean,所以使用@Autowired肯定为null了
解决方案
用ApplicationContext去获取bean。
法1:根据Class获取
法2:根据bean名称(注意名称为实现类而不是接口)去获取bean
工具类写法
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context)
throws BeansException {
ApplicationContextHolder.context = context;
}
public static ApplicationContext getContext() {
return context;
}
}
不在同一个上下文
案例1:websocket
复现
websocket 里面使用 @Autowired 注入 service 或 bean 时,报空指针异常,service 为 null。
解决方案:将要注入的 service 改成 static,就不会为null了
@Controller
@ServerEndpoint(value="/chatSocket")
public class ChatSocket {
// 这里使用静态,让 service 属于类
private static ChatService chatService;
// 注入的时候,给类的 service 注入
@Autowired
public void setChatService(ChatService chatService) {
ChatSocket.chatService = chatService;
}
}
分析
概述:spring管理的都是单例(singleton),和 websocket (多对象)相冲突。
详解:项目启动时会初始化 websocket (非用户连接的),spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。但是,由于 spring 默认管理的是单例,所以只会注入一次 service。当新用户进入聊天时,系统又会创建一个新的 websocket 对象,这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。
像 controller 里面有 service, service 里面有 dao。因为 controller,service ,dao 都是单例,所以注入时不会报 null。但是 websocket 不是单例,所以使用spring注入一次后,后面的对象就不会再注入了,会报null。
案例2:TokenMapper
复现
写一个工具类,里面用了@Autowired注入了TokenMapper以及TokenService时,在TokenMapper的findFirstById()方法一直报 java.lang.nullpointerexception 异常
解决方案
@Component // 关键1,将该工具类注册为组件
public class TokenUtil {
@Autowired
private TokenMapper tokenMapper;
@Autowired
private TokenService tokenService;
public static TokenUtil tokenUtil; // 关键2
public TokenUtil() {
}
// 关键3
@PostConstruct
public void init() {
tokenUtil = this;
tokenUtil.tokenMapper = this.tokenMapper;
}
// ...
}
1. public static TokenUtil tokenUtil; // 注意这个为 public 不然没有权限
分析
静态方法使用静态注入的变量
问题
一般工具类中的方法都是静态的,而在静态方法中又不能直接使用注入的mapper。如:
//注入
@Autowired
private SmsLogMapper mapper;
//方法
public static String sendSms(String mobile) {
//这里不能直接用mapper,因为mapper不是静态
}
如果把mapper改为静态的,则在方法中使用时,mapper就是null。
解决方法
在工具类上添加@Component注解将工具类实例到spring容器中;
使用@PostConstruct注解初始化工具类和mapper,如下:
@Component
public class SendSms{
@Autowired
private SmsLogMapper mapper;
//当前工具类
private static SendSms sendSmsUtil;
//解决静态方法中不能直接用mapper的问题
@PostConstruct
public void init() {
sendSmsUtil = this;
sendSmsUtil.mapper = this.mapper;
}
}

请先 !