@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取到的值。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论