在spring工程中,我们经常需要使用到配置文件的一些信息,在每个类中定义,可能导致这些信息变得零散。spring给我们提供了一个注解@Value(),使我们可以注入配置文件中的数据。
bootstrap.yml
jay:
key: www.baidu.com
如果你想在你的工具类中注入这个变量,那么你可能面临问题,方法是static
的,那么你需要使用静态变量作为参数在方法中使用。
错误示范:
public class testUtils{
@Value("${jay.key}")
private static String url;
}
正确示范
@Configuration
public class testUtils{
private static String url;
@Value("${jay.key}")
public void setUrl(String url) {
url= url;
}
}
通过@Component和在Setter上打上注解,即可将配置文件的信息注入到静态变量中了.
为什么会出现空指针?
先说结论: Spring从源码层面不提供对static
修饰符的成员变量进行注入.
- AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata
/**
* 解析当前Class被@Autowired标记的成员
* @param clazz
* @return
*/
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
// 递归遍历当前类及其所有基类,解析全部注解元信息
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 收集被@Autowired、@Value标记的Field.
// 利用反射机制获取给定类中所有的声明字段,获取字段上的注解信息
// doWithLocalFields->获取当前类的所有Field,每个field执行lambda内的逻辑.
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 此处逻辑较为复杂,通过debug发现如果为被标注的属性,会返回required:true.
// 大致的意思是这个field是否被特定的注解标记?这里留一个疑问
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
// 如果是static属性的成员,Spring不提供支持
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
// 判断required的状态
boolean required = determineRequiredStatus(ann);
// 将当前成员添加进currElements
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 省略....
}
static的变量是归属于Class的,而Spring容器上下文只对Java对象进行管理,Spring不鼓励对static变量做注入Bean的操作,因此如果需要在某些工具类中将Bean赋值给静态变量,可以使用构造注入的方式. 或者使用
@PostConstruct
作为桥梁.
想深入的朋友可以看看这篇文章: 想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做
网友评论