@Autowired不能加在静态成员变量上要不然会注入为null

项目场景:

最近接到一个需求对大数据进行Excel导出,打算多线程分sheet页导出


问题描述

测试过程中发现声明的静态成员变量用 @Autowired 注入 bean 为 null
(因为是在工具类中我定义的工具类方法是静态的 所以成员变量也需要定义为静态)
错误demo部分代码如下

package com.ruoyi.common.utils.poi;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;


@Component
public class ExcelXSSFNewUtil {
    
    @Autowired
    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;
    
    public static void exportXlsxBigInfo(String[] headName, String[] headId, List list, String fileName, HttpServletResponse response) throws Exception {
        //测试默认两条一页
        int num = 2;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        int dataCount = list.size();
        //任务数(向下取整)
        int taskNext = dataCount / num;
        //余数
        int modeCount = dataCount % taskNext;
        //每个线程有个sheet用开始结束分割数据
        int start = 0;
        int end = 0;
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        CountDownLatch countDownLatch = new CountDownLatch(taskNext);
        for (int t = 0; t < taskNext; t++) {
            start = t * num;
            //最后一页加上余数
            if (t == taskNext - 1) {
                end = (t + 1) * num + modeCount;
            } else {
                end = (t + 1) * num;
            }
            List subList = list.subList(start, end);
            //这个方法线程不安全放外面
            SXSSFSheet sheet = workbook.createSheet(start + 1 + "-" + end);
            threadPoolTaskExecutor.execute(() -> {
                try {
                    Row row1 = sheet.createRow(0);
                    for (int j = 0; j < headName.length; j++) {
                        Cell cell = row1.createCell(j);
                        cell.setCellValue(headName[j]);
                    }
                    Object obj = null;
                    Map map;
                    for (int i = 1; i <= subList.size(); i++) {
                        Row row = sheet.createRow(i);
                        obj = subList.get(i - 1);
                        map = objectToMap(obj);
                        for (int j = 0; j < headId.length; j++) {
                            Cell cell = row.createCell(j);
                            XSSFRichTextString text = null;
                            String head = null;
                            String dictName = null;
                            head =String.valueOf(map.get(headId[j]));
                            if ("".equals(head) || head == null) {
                                text = new XSSFRichTextString("");
                            } else {
                                Field field = obj.getClass().getDeclaredField(headId[j]);
                                boolean b = field.isAccessible();
                                field.setAccessible(true);
                                if (field.get(obj) instanceof Date) {
                                    String a = sdf.format(field.get(obj));
                                    text = new XSSFRichTextString(a);
                                } else {
                                    text = new XSSFRichTextString(head);
                                }
                                field.setAccessible(b);
                            }
                            cell.setCellValue(text);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        File file = new File("C:\\Users\\14377\\Videos\\Captures\\" + fileName);
        FileOutputStream os = new FileOutputStream(file);
        workbook.write(os);
        os.flush();
        os.close();
//        response.setContentType("application/octet-stream;charset=UTF-8");
//        response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
//        response.setCharacterEncoding("UTF-8");
//        ServletOutputStream outputStream = response.getOutputStream();
//        workbook.write(outputStream);
//        outputStream.flush();
//        outputStream.close();
    }

    private static void addValidate(SXSSFSheet sheet, List<String> list, String head, int column) {
        DataValidationHelper helper = sheet.getDataValidationHelper();
        //区域
        CellRangeAddressList regions = new CellRangeAddressList(3, 5000, column, column);
        // 生成下拉框内容
        DataValidationConstraint constraint = helper.createFormulaListConstraint(String.valueOf(list));
        // 绑定下拉框和作用区域
        DataValidation validation = helper.createValidation(constraint, regions);
        validation.setShowErrorBox(true);
        validation.createErrorBox("警告", head + "选择有误");
        sheet.addValidationData(validation);
    }

    public static Map<String, Object> objectToMap(Object object) {
        Map<String, Object> dataMap = new HashMap<>();
        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            try {
                field.setAccessible(true);
                dataMap.put(field.getName(), field.get(object));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return dataMap;

    }
}

    @PostMapping("/export")
    public void export(HttpServletResponse response, SysUser user) throws Exception {
        List<SysUser> list = userService.selectUserList(user);
     ExcelXSSFNewUtil.exportXlsxBigInfo(USER_NAME,USER_ID,list,"用户信息.xlsx",response);
    }
private static final String[] USER_NAME = new String[]{"用户序号","部门编号","登录名称","用户名称","用户邮箱","手机号码","用户性别","帐号状态","最后登录IP","最后登录时间"};

private static final String[] USER_ID = new String[]{"userId","deptId","userName","nickName","email","phonenumber","sex","status","loginIp","loginDate"};


原因分析:

这篇文章写的比较好

https://blog.csdn.net/asd43211234/article/details/106824230?spm=1001.2014.3001.5506


原因大概有一下两点
1.在Java中,针对static静态成员,我们有一些最基本的常识:静态变量(成员)它是属于类的,而非属于实例对象的属性;同样的静态方法也是属于类的,普通方法(实例方法)才属于对象。而Spring容器管理的都是实例对象,包括它的@Autowired依赖注入的均是容器内的对象实例,所以对于static成员是不能直接使用@Autowired注入的。
就是 类成员的初始化较早,那时候实例对象还没有 就不存在注入成功了
2.看源码
扫描Class类需要注入的元数据的时候,直接选择忽略掉了static成员(包括属性和方法)。
![在这里插入图片描述](https://img-blog.csdnimg.cn/7803c7b72cde478fb0af15b5c6ae1bf0.png

解决方案:

间接实现static成员注入 延迟为static成员属性赋值
方法一:set方法注入

@Component
public class ExcelXSSFNewUtil {

    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    public void setMbsTaskExecutor(@Qualifier("threadPoolTaskExecutor") ThreadPoolTaskExecutor taskExecutor) {
        ExcelXSSFNewUtil.threadPoolTaskExecutor = taskExecutor;
    }

方法二:使用@PostConstruct注解

@Component
public class ExcelXSSFNewUtil {

    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private  ThreadPoolTaskExecutor taskExecutor;
    @PostConstruct
    public void init() {
        ExcelXSSFNewUtil.threadPoolTaskExecutor = taskExecutor;
    }

@PostConstruct注解介绍:

初始化方式一:@PostConstruct注解
假设类UserController有个成员变量UserService被@Autowired修饰,那么UserService的注入是在UserController的构造方法之后执行的。

    如果想在UserController对象生成时候完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入的对象,那么就无法在构造函数中实现(ps:spring启动时初始化异常),例如:
public class UserController {
	@Autowired
	private UserService userService;
 
	public UserController() {
		// 调用userService的自定义初始化方法,此时userService为null,报错
		userService.userServiceInit();
	}
}
    因此,可以使用@PostConstruct注解来完成初始化,@PostConstruct注解的方法将会在UserService注入完成后被自动调用。
public class UserController {
	@Autowired
	private UserService userService;
 
	public UserController() {
	}
 
	// 初始化方法
	@PostConstruct
	public void init(){
		userService.userServiceInit();
	}
}

总结:类初始化调用顺序:

(1)构造方法Constructor
(2)@Autowired
(3)@PostConstruct

初始化方式二:实现InitializingBean接口
除了采用注解完成初始化,也可以通过实现InitializingBean完成类的初始化

public class UserController implements InitializingBean {
	@Autowired
	private UserService userService;
 
	public UserController() {
	}
 
	// 初始化方法
	@Override
	public void afterPropertiesSet() throws Exception {
		userService.userServiceInit();
	}
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小瞿码上有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值