java静态方法里使用spring的注入对象方式

 更新时间:2026年04月24日 09:25:12   作者:单人影i  
本文分析了在使用Spring框架时,静态方法中引用非静态变量导致空指针的问题,并提出了使用`@PostConstruct`注解、`@Value`注解、构造注入和`InitializingBean`接口等解决方案

@Resource 导入应用场景

大家都知道,Java静态资源(静态代码块,静态方法,静态属性)在类加载的时候进行加载,那么加载时机肯定是在spring对象注入之前的,所以我们在调用实际的静态方法时就会出现空指针。

这种可能在实际开发中出现在我们的util工具类中.

IDEA编译报错原因

  • 静态方法里边引用了非静态变量 distributeIdClient,这个会直接报错的

* 应该不会有人认为在注入上面加 static 就不会报错了吧. QAQ,

  • 静态方法中引用的 distributeIdClient 虽然用了@Resource注解,但是该注解的注入是在静态方法加载之后执行的,所以此处的 distributeIdClient 在使用时为null
  • 当一个类包含了@Resource的子类时,他就必须交给spring来处理而不能使用new来初始化,否则会导致他的自动装配的子类为null。所以如果使用注解的方式,那么我们这个IdWorkerUtils类就需要加上@component注解来交给spring进行初始化

解决方案

使用PostConstruct注解 PostConstruct 标注方法执行时机

完成依赖注入以执行任何初始化之后,在类投入服务之前调用, 即: 在spring项目中,在一个bean的初始化过程中,方法执行先后顺序为

  • Constructor > @Autowired > @PostConstruct
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * @description: id工具类
 * @author: 单人影
 * @create: 2022-09-15 14:04
 **/
@Component
@Slf4j
public class IdWorkerUtils {

    private static IdWorkerUtils utils;

    @Resource
    private DistributeIdClient distributeIdClient;

    @PostConstruct
    public void init() {
        utils = this;
        utils.distributeIdClient = this.distributeIdClient;
    }

    public static String getId() {
        try {
            Result<String> result = utils.distributeIdClient.stringNum();
            log.info("请求id服务获取请求id,响应结果:{}", JacksonUtil.objectToString(result));
            if (result != null && result.getIsSuccess() && StringUtils.isNotEmpty(result.getData())) {
                return result.getData();
            }
        } catch (Exception e) {
            log.warn("请求id服务获取请求id 异常", e);
        }
        return IdWorker.getIdStr();
    }
}

在静态方法中 使用@value注解的值

@Component
public class XmlUtils {
	
	//@Value只能给普通变量注入值,不能给静态变量赋值,不能直接在这里写@Value,这些直接注入就是null
  @Value("${xml.encoded:UTF-8}")
	public static String xmlEncoded;

}

解决办法

/**
 * @description: xml utils
 * @author:  单人影
 * @create: 2022-10-12 10:23
 **/
@Slf4j
@Component
public class XmlUtils {

    private static String xmlEncoded;

    public String getXmlEncoded() {
        return xmlEncoded;
    }
	 
	 // 注意: 构造方法不能 是static 的
    @Value("${xml.encoded:UTF-8}")
    public void setXmlEncoded(String xmlEncoded) {
        XmlUtils.xmlEncoded = xmlEncoded;
    }



    /**
     * @Description: 将 xml 字符串转换成对象
     * @Param: [xmlText, clazz]
     * @return: T
     * @Author: 单人影
     * @Date: 2022/10/12 10:24
     */
    public static <T> T parseXmlStringToObj(String xmlText, Class<T> clazz) {
        return JAXB.unmarshal(new StringReader(xmlText.trim()), clazz);
    }


    /**
     * 将对象转换成 xml 字符串
     *
     * @param obj   对象
     * @param clazz 对象的类型
     * @return xml 字符串
     */
    public static <T> String parseObjToXmlString(T obj, Class<T> clazz) {
        String result = StringUtils.EMPTY;
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = jaxbContext.createMarshaller();
            // 格式化输出
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            // 编码格式
            marshaller.setProperty(Marshaller.JAXB_ENCODING, xmlEncoded);
            // 去掉默认报文头
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            // 不进行转义字符的处理
            marshaller.setProperty(CharacterEscapeHandler.class.getName(), (CharacterEscapeHandler) (ch, start, length, isAttVal, writer) -> writer.write(ch, start, length));
            StringWriter writer = new StringWriter();
            // 将对象转换成 xml 字符串,存入 writer 中
            marshaller.marshal(obj, writer);
            result = writer.toString();
        } catch (JAXBException e) {
            log.error("将对象转换成xml字符串失败", e);
        }
        if (StringUtils.isEmpty(result)) {
            throw new RuntimeException(String.format("将 【%s】 类型的对象转换成 xml 文本失败", clazz.getName()));
        }
        return result;
    }

}

方案解释

static的变量是归属于Class的,而Spring容器上下文只对Java对象进行管理,Spring不鼓励对static变量做注入Bean的操作,因此如果需要在某些工具类中将Bean赋值给静态变量,可以使用构造注入的方式. 或者使用@PostConstruct作为桥梁 同@resource. 或者 实现 InitializingBean 重写 afterPropertiesSet 实现给静态类 赋值

// afterPropertiesSet 示例  容器初始化的时候给静态属性赋值

@Component
public class XmlUtils implements InitializingBean{
	
	public static String XML_ENCODED;
	
    @Value("${xml.encoded:UTF-8}")
	public String xmlEncoded;

	@Override
	public void afterPropertiesSet() throws Exception {
		XML_ENCODED= xmlEncoded;
	}
}

调用过程:@Comment组件在springboot启动的时候就被扫描到,并且@Value实现注入,相当于将xmlEncoded获取到的值传给工具类中的属性,因此可以在工具类中,直接调用这个类的属性,获取到@Value取到的值。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Springboot常用方法参数注解示例详解

    Springboot常用方法参数注解示例详解

    这篇文章主要介绍了Springboot常用方法参数注解及示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 通过源代码分析Mybatis的功能流程详解

    通过源代码分析Mybatis的功能流程详解

    这篇文章主要介绍了通过源代码分析Mybatis的功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • SpringBoot3配置Logback日志滚动文件的方法

    SpringBoot3配置Logback日志滚动文件的方法

    本文介绍了在SpringBoot3中配置Logback日志滚动文件的方法,因为SpringBoot3内置的logback版本是1.4.14,之前使用SpringBoot2.1.5的logback配置发现有些东西不能生效了,需要的朋友可以参考下
    2024-08-08
  • Spring核心IoC和AOP的理解

    Spring核心IoC和AOP的理解

    本文主要介绍了Spring核心IoC和AOP的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-03-03
  • Spring AI Alibaba接入大模型时的依赖问题小结

    Spring AI Alibaba接入大模型时的依赖问题小结

    文章介绍了如何在pom.xml文件中配置SpringAI Alibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓库镜像设置为阿里云以提高下载速度,具体配置方法跟随小编一起学习下吧
    2025-02-02
  • Java中Lombok工具库使用的技术指南

    Java中Lombok工具库使用的技术指南

    Lombok 是 Java 开发中常用的工具库,通过注解的方式大大简化了代码开发,本篇文章将从基础入门到高级用法,深入讲解 Lombok 的使用技巧和注意事项,快跟随小编一起来学习一下吧
    2025-04-04
  • SpringBoot利用@Validated注解优雅实现参数校验

    SpringBoot利用@Validated注解优雅实现参数校验

    在开发 Web 应用时,用户输入的合法性校验是保障系统稳定性的基础,​Spring Boot 的 @Validated 注解 提供了一种更优雅的解决方案,下面就跟随小编一起学习一下吧
    2025-04-04
  • Intellij IDEA根据maven依赖名查找它是哪个pom.xml引入的(图文详解)

    Intellij IDEA根据maven依赖名查找它是哪个pom.xml引入的(图文详解)

    这篇文章主要介绍了Intellij IDEA根据maven依赖名查找它是哪个pom.xml引入的,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • CountDownLatch同步工具类使用详解

    CountDownLatch同步工具类使用详解

    这篇文章主要为大家详细介绍了CountDownLatch的使用说明,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-04-04
  • Java 中的 BufferedReader 介绍_动力节点Java学院整理

    Java 中的 BufferedReader 介绍_动力节点Java学院整理

    BufferedReader 是缓冲字符输入流。它继承于Reader。接下来通过本文给大家介绍BufferedReader的相关知识,需要的朋友参考下吧
    2017-05-05

最新评论