@Autowired注解能用在static属性吗?autowired注入static属性上为null

@Autowired注解能用在static属性吗?

答案是否定的,我们来测试下:
ddfa41e91c548717435e5e9fb7879e16.png

日志信息已经很明确了,表示static不能被@Autowired进行复制。为什么呢?我们现在就来一起了解其原因。

首先将我们的测试环境搭建好,

User1类

@Componentpublic 
class User1 {  @Autowired private static User2 user2; @Autowired  private User2 user3;
}

User2类

@Componentpublic 
class User2 {}

AppConfig类

@Configuration@ComponentScan("staticDemo")
/*@EnableAspectJAutoProxy*/
/*@Import(MyImportBeanDefinitionRegistrar.class)*/
public class AppConfig {}

Test类

public class Test {    public static void main(String[] args) {      AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(AppConfig.class);    }
}

然后将代码定位在依赖注入的入口
6a0ca3ca981e055dc133cdc4265cf53f.png

此时我们的beanName是User1类,我们需要注入User1类,然后我们进入这个方法

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {    if (bw == null) {      if (mbd.hasPropertyValues()) {        throw new BeanCreationException(            mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");      }      else {        // Skip property population phase for null instance.        return;      }    }    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the    // state of the bean before properties are set. This can be used, for example,    // to support styles of field injection.    //Spring判断你是不是自己实现了InstantiationAwareBeanPostProcessor,如果实现了,而且返回false,    // Spring就不会继续执行了,一般不会用到    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {      for (BeanPostProcessor bp : getBeanPostProcessors()) {        if (bp instanceof InstantiationAwareBeanPostProcessor) {          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {            return;          }        }      }    }    //判断是否已经对属性赋值    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);    //判断属性植入的模式,默认NO    int resolvedAutowireMode = mbd.getResolvedAutowireMode();    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);      // Add property values based on autowire by name if applicable.      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {        autowireByName(beanName, mbd, bw, newPvs);      }      // Add property values based on autowire by type if applicable.      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {        autowireByType(beanName, mbd, bw, newPvs);      }      pvs = newPvs;    }    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);    PropertyDescriptor[] filteredPds = null;    if (hasInstAwareBpps) {      if (pvs == null) {        pvs = mbd.getPropertyValues();      }      //这里才是通过后置处理器完成属性注入的工作      for (BeanPostProcessor bp : getBeanPostProcessors()) {        if (bp instanceof InstantiationAwareBeanPostProcessor) {          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;          PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);          if (pvsToUse == null) {            if (filteredPds == null) {              filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);            }            pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);            if (pvsToUse == null) {              return;            }          }          pvs = pvsToUse;        }      }    }    if (needsDepCheck) {      if (filteredPds == null) {        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);      }      checkDependencies(beanName, mbd, filteredPds, pvs);    }    if (pvs != null) {      applyPropertyValues(beanName, mbd, bw, pvs);    }  }

这里有两个for循环,我们关注第二个for循环,找到后置处理器是
301d2b1b4b61bad499515cd0e3600f80.png

然后点进去

54f00e283a56c4199f830217b588394b.png

这里第一行代码就是获取我们的数据信息,并且用InjectionMetadata的方式进行封装,获取InjectionMetadata后就可以通过反射的方式进行属性注入了,这里在前面的Spring源码章节我们已经详细介绍了,就不再叙述。我们进入这个findAutowiringMetadata方法,瞧一瞧他是如何获取的,

0357b4dbd0f824c59cc67b389f3ae2a1.png

我们看到InjectionMetadata封装了哪些信息,其中包含了我们的user3这个属性,注意这个user3是没有static修饰的,user2是被static修饰了的,而这里确没有user2这个属性,先记住这一点,然后我们再看我们的metadata是通过injectionMetadataCache缓存获取的,说明一个我们的static是在存放缓存的时候就将我们的static属性屏蔽掉,接下来我们就验证我们的猜想。

Spring何时屏蔽static属性?

我们将代码定位在AbstractAutowireCapableBeanFactory.doCreateBean方法

68dbf64c4fd1f2cce6c11419063d4020.png

跟踪进去

47ea23a73e9161ed725cb84e1c78e0fa.png

再跟踪

9e6c0e6b3b264dae426968e732cc5674.png

可以看到已经回到了我们find方法,点进去,注意下面的红线表示我们这里是找的user1类的属性

6ec38299c0a83eeab336073ef6f66634.png

然后这里我们关注的是injectionMetadataCache缓存

70da642d14d61a63227ed88bc3984de5.png

此时缓存里并没有user1的元信息,我们再次跟进

5bdcad878252001dcd8e4f7eb3edcbe2.png

首先看到这里ReflectionUtils.doWithLocalFields,我们点进去

7c36b077ae42d1dd2a9e746ce9aba352.png可以看到这里获取了两个我们的属性,一个是静态属性一个是常态属性,然后我们再回到buildAutowiringMetadata方法,注意这里的filed是函数试变成,它会回调这里的代码

832d0f389a8353a8a5f737752a1c2942.png我们就可以看到如果我们的属性是static,那么Spring会直接抛弃,

e94efcbd288cd5df7edd508518c7e50b.png可以看到我们已经得到了验证,Spring就是在这里抛弃了static的属性,至于为什么要抛弃static属性呢?笔者猜测这里需要回到JVM的一些知识,我们都知道static是面向类级别,而Spring通常是面向普通的单例对象,如果我们将单例的对象中static属性赋值,那么就会影响我们这个类的其他对象的值,个人认为这是Spring不希望看到的,这也是不科学的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux下用c语言写黄金矿工,C语言写的黄金矿工O(∩_∩)O---初稿,能玩了

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼int main(void){initgr();go();getch();closegr();return 0;}void youxiye() /* 游戏页 */{setfillstyle(SOLID_FILL,15);bar(0,0,639,49);setfillstyle(SOLID_FILL,6);bar(0,49,639,349);setcolor(BLUE);line(0,49,638,49);setc…

Swagger介绍及使用

导语: 相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端&…

linux 安装libcurl4-gnutls-dev,curl / curl.h,libcurl,libcurl4-openssl-dev,libcurl4-nss-dev库之间的区别?...

我有以下curl标题,我仍然可以安装上面提到的libcurl4包 –kafkaMetamorphosis:~$ll /usr/include/curl/total 200drwxr-xr-x 2 root root 4096 Jan 16 13:29 ./drwxr-xr-x 51 root root 20480 Jan 16 13:29 ../-rw-r--r-- 1 root root 7303 Dec 18 01:11 curlbuild.h-rw-r--r--…

c语言输入四个成绩求最高分最低分,数组实现学生成绩录入、求最高分、最低分、平均分和排序...

/*使用数组实现10名学生的成绩录入,并输出这10名学生中成绩的最高分最低分平均分按照分数从大到小排序思考:如何实现从小到大排序?如果学院有5个班,每个班30人,如何处理?求所有成绩中的最高分是哪个班的&am…

c语言课设宿舍管理程序,C语言程序课程设计宿舍管理软件.doc

C语言程序课程设计宿舍管理软件.doc课程设计(论文)题 目 名 称 宿舍管理软件课 程 名 称 C语言程序课程设计学 生 姓 名学 号系 、专 业 信息工程系、信息大类指 导 教 师 黄 同 成目 录1 前言2 需求分析62.1要求62.2任务2.3运行环境2.4开发工具3 概要设计与详细设计73.1设计原…

接口文档生成工具Swagger2的使用

一、什么是Swagger Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保…

Netty详解

一.Netty介绍 1.什么是netty Netty 是由 JBOSS 提供的一个 Java 开源框架。Netty 提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架,Netty 在互联网领域、大数据分布式计算…

有没有检查c语言编译错误的软件,求大佬解答,为什么这个程序编译软件检查不出错误...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include#include /* malloc()等 */#include#include#include /* exit() */#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW -2typedef int Status; /* Status是函数的类型,其值是函数结果状态代码&…

语法分析器c语言实验报告,词法分析实验报告(C++)..doc

词法分析实验报告(C).词法分析实验报告一、实验目的1. 掌握词法分析的原理。2. 熟悉保留字表等相关的数据结构与单词的分类方法。3. 掌握词法分析器的设计与调试。二、实验内容根据编译中的分词原理,用C语言编写一个C语言的词法分析程序:.三、实验要求1. 输入:任意一个C语言程序…

详解 Java NIO

详解 Java NIO 文件的抽象化表示,字节流以及字符流的文件操作等属于传统 IO 的相关内容,我们已经在前面的文章进行了较为深刻的学习了。 但是传统的 IO 流还是有很多缺陷的,尤其它的阻塞性加上磁盘读写本来就慢,会导致 CPU 使用…

转专业计算机c语言,转专业申请美国计算机专业研究生必须要做的准备

先修课——转专业申计算机时,补先修课是使自己match的重要的一步。1.纽约大学的计算机硕士项目(计算机系的M.S. in Computer Science和M.S. in Information Systems项目)对申请人的先修课要求:The minimum prerequisite background for admission to the…

使用between and查找时间范围时的日期边界问题

最近在一个项目的后台数据库查找中,需要根据表中的时间字段查找某一范围内的数据(7天、15天、30天),这时我想用between and(其实使用DateDiff函数就可以完成,详情请看另一片文章:SQL查询今天、昨…

c语言画爱心附带解释,用C语言画一个“爱心”

/*每个main函数代表一种形状*/#includeusing namespacestd;#include#include/*int main(void){for(float y 1.5f;y > -1.5f;y - 0.06f){for(float x -1.5f;x < 1.5f;x 0.03f){float a x * x y * y - 1;putchar(a * a * a - x * x * y * y * y < 0.0f?^: );}putc…

SQL查询今天、昨天、7天内、30天

今天的所有数据&#xff1a;select * from 表名 where DateDiff(dd,datetime类型字段,getdate())0 昨天的所有数据&#xff1a;select * from 表名 where DateDiff(dd,datetime类型字段,getdate())1 7天内的所有数据&#xff1a;select * from 表名 where DateDiff(dd,dateti…

C语言入门I love China,C语言从入门到精通

如何学习C语言 Ⅰ第1篇 基础知识开启C语言编程世界之门。第1章 步入C的世界——Hello C 2视频教学录像&#xff1a;1小时34分钟你可能已经听说或知道一点C语言&#xff0c;也可能没有任何基础&#xff0c;没关系&#xff0c;本章就带领你进入C语言的编程世界。1.1 了解C语…

电气工程及其自动化学不学c语言,电气工程及其自动化学什么 就业方向有哪些...

电气工程及其自动化学什么 就业方向有哪些2019-05-05 11:16:29文/刘美娟电气工程及其自动化专业是电气信息领域的一门新兴学科&#xff0c;触角伸向各行各业&#xff0c;小到一个开关的设计&#xff0c;大到宇航飞机的研究&#xff0c;都有它的身影。由于和人们的日常生活以及工…

Tomcat(一):简介

一、概念 Tomcat 服务器是一个开源的轻量级Web应用服务器&#xff0c;在中小型系统和并发量小的场合下被普遍使用&#xff0c;是开发和调试Servlet、JSP 程序的首选。 二、原理 Tomcat结构图&#xff1a; ​ Tomcat主要组件&#xff1a;服务器Server&#xff0c;服务Serv…

Tomcat(二):server.xml配置

一、server.xml详解 Tomcat各组件关系图 ​ 1、Server ​ server.xml的最外层元素。 常用属性&#xff1a; ​ port&#xff1a;Tomcat监听shutdown命令的端口。 ​ shutdown&#xff1a;通过指定的端口&#xff08;port&#xff09;关闭Tomcat所需的字符串。修改shutd…

c语言的表达式2 4 6 8的值,C语言程序设计测试题二

一、判断题(每题2分&#xff0c;共8分)1.若有int ⅰ10, j0; 则执行完语句if (j0)ⅰ ; else ⅰ- -;ⅰ的值为11。()2.若有 int ⅰ5, j10; 则执行完语句switch ( i ){case 4: j ;case 5: j- - ;case 6: j ;case 7: j- 2;default: ;}后j的值为8。 ( )3.若有 int i10, j2;则执行完ⅰ…

Tomcat(三):日志

一、Tomcat 日志概述 日志分为两种&#xff0c;系统日志和控制台日志。 系统日志主要包含运行中日志和访问日志&#xff0c;分为5类&#xff1a;catalina、localhost、manager、localhost_access、host-manager。在logging.properties文件中进行配置。 控制台日志包含了cata…