• java 静态方法里边如何使用spring的注入对象


    @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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

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

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

    解决办法

    
    /**
     * @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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    方案解释:

    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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

  • 相关阅读:
    13.java中的抽象类和接口[20220622]
    云链商城连锁门店新零售O20系统以零售商城
    Vue2 零基础入门 Vue2 零基础入门第六天 6.1 前端路由的概念与原理 && 6.2 vue-router的基本使用
    【C++】红黑树的模拟实现
    springboot + vue实战
    vue+elementui网上线上教学平台python+java
    halcon之区域:多种区域(Region)生成(4)
    分享一下奶茶店怎么在小程序上做商城功能
    45_System类
    华为 连接OSPF和RIP网络---OSPF和RIP网络相互引入
  • 原文地址:https://blog.csdn.net/a185589690/article/details/126870606