所有分类
  • 所有分类
  • 未分类

Spring-IOC常见问题

简介

本文介绍Spring的IOC常见的问题。

注入为null

使用@Autowired注入bean的时候,有时注入失败,bean为null,主要有以下几种原因:

  1. 注入的类没有加入容器。比如:没加@Component,没被加入到SpringBoot包扫描路径
  2. 在特殊bean中注入:Filter、Listener
  3. 不在一个上下文中
  4. 静态方法使用静态注入的变量

特殊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;
    }
}
0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录