Spring 注入 bean 的 set 方法不能是 static 的

华为Atlas 300I推理卡驱动安装避坑指南:不同安装方式的选择与优化 本文详细解析华为Atlas 300I推理卡驱动安装的三种主流方式(.run、.rpm和源码编译),提供关键环境检查步骤、安装流程优化建议及常见问题解决方案,帮助开发者高效完成芯片推理卡部署并规避典型安装陷阱。 阅读详情

一、简述

静态方法是属于类(class)的,普通方法属于实体对象(也就是 new 出来的对象)。Spring 注入是在容器中实例化对象,所以不能使用静态方法。Springframework 里,不能@Autowired一个静态变量,使之成为一个 Spring bean。例如下面这样:

@Autowired  
private static OurBean ourBean;  

ourBean 在这种状态下不能够被依赖注入,会抛出java.lang.NullPointerException。因为静态变量/类变量不是对象的属性,而是一个类的属性,Spring 是基于对象层面上的依赖注入。

使用静态变量/类变量扩大了静态方法的使用范围。静态方法在 Spring 是不推荐使用的。依赖注入的主要目的,是让容器去产生一个对象的实例。然后在整个生命周期中使用它们,同时也让工作更加容易。

一旦使用静态方法,就不再需要去产生这个类的实例。同时也不能为该类,依靠注入方式去产生多个具有不同的依赖环境的实例。这种 static field 是隐含共享的,并且是一种 global 全局状态,Spring 同样不推荐这样去做。

编程中最常用的模式就是单例模式了,然而单例模式都用在什么场合?为什么不用静态方法而要用单例模式呢?要搞清这些问题,需要从静态方法和非静态方法的区别和联系说起。

二、静态方法常驻内存,非静态方法只有使用的时候才分配内存?错

一般都认为是这样,并且怕静态方法占用过多内存而建议使用非静态方法,其实这个理解是错误的。为什么会这样,先从内存分配开始说起:

托管堆的定义:对于 32 位的应用程序来说,应用程序完成进程初始化后, CLR 将在进程的可用地址空间分配一块保留的地址空间,它是进程(每个进程可使用4GB)中可用地址空间上的一块内存区域,但并不对应任何物理内存,这块地址空间即是托管堆。

托管堆有分为多个区域,其中最重要的是垃圾回收堆(GC Heap)和加载堆(Loader Heap)。GC Heap 用于存储对象实例,受 GC 管理;Loader Heap 又分为 High-Frequency Heap、Low-Frequency Heap 和 Stub Heap,不同的堆上又存储不同的信息。Loader Heap 最重要的信息就是元数据相关的信息,也就是 Type 对象,每个 Type 在 Loader Heap 上体现为一个 Method Table(方法表),而 Method Table 中则记录了存储的元数据信息,例如基类型、静态字段、实现的接口、所有的方法等等。Loader Heap 不受 GC 控制,其生命周期为从创建到 AppDomain 卸载。(摘自《你必须知道的.Net》)

由此,静态方法和非静态方法,在内存里其实都放在 Method Table 里了,在一个类第一次被加载的时候,它会在 Loader Heap 里把静态方法,非静态方法都写入 Method Table 中,而且 Loader Heap 不受 GC 控制,所以一旦加载,GC 就不会回收,直到 AppDomain 卸载。

当然,静态方法和非静态方法,它们都是在第一次加载后就常驻内存,所以方法本身在内存里,没有什么区别。所以也就不存在“静态方法常驻内存,非静态方法只有使用的时候才分配内存”这个结论了。

三、静态方法和非静态方法的区别

在内存中的区别是,非静态方法在创建实例对象时,因为属性的值对于每个对象都各不相同,因此在 new 一个实例时,会把该实例属性在 GC Heap 里拷贝一份,同时这个 new 出来的对象放在堆栈上,堆栈指针指向了刚才拷贝的那一份实例的内存地址上。而静态方法则不需要,因为静态方法里面的静态字段,就是保存在 Method Table 里了,只有一份。

因此静态方法和非静态方法,在调用速度上,静态方法速度一定会快点,因为非静态方法需要实例化,分配内存,但静态方法不用。这种速度上差异可以忽略不计。

四、为什么要有非静态方法

早期的结构化编程,几乎所有的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建 c++、Java 和 c# 这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。
接下来继续思考,如果全部用静态方法,不用非静态方法,不是一样能实现功能吗?没错,但是这样代码是基于对象,而不是面向对象的,因为面向对象的继承和多态,都是非静态方法。
第二个原因,多线程的情况下,如果静态方法使用了一个静态字段,这个静态字段可以会被多个线程修改,因此说如果在静态方法里使用了静态变量,这就会有线程安全问题。当然了,就算不是多线程,因为静态字段只有一份,同样会有被其他地方修改的问题。

五、总结

1️⃣什么时候用静态方法,什么时候使用非静态方法

既然静态方法和实例化方式的区分是为了解决模式的问题,如果考虑不需要继承和多态的时候,就可以使用静态方法,但就算不考虑继承和多态,就一概使用静态方法也不是好的编程思想。
从另一个角度考虑,如果一个方法和所在类的实例对象无关,那么它就应该是静态的,否则就应该是非静态。因此像工具类,一般都是静态的。

2️⃣为什么使用单例模式而不用静态方法

从面向对象的角度讲:
虽然都能实现目的,但是它们一个是基于对象,一个是面向对象的。如果一个方法和它所在类的实例对象无关,那么它就应该是静态的,反之它就应该是非静态的。如果确实应该使用非静态的方法,但是在创建类时又确实只需要维护一份实例时,就需要用单例模式了。
比如说在系统运行时候,就需要加载一些配置和属性,这些配置和属性是一定存在了,又是公共的,同时需要在整个生命周期中都存在,所以只需要一份就行。这个时候就需要单例模式或静态方法去维持一份且仅这一份拷贝,但此时这些配置和属性又是通过面向对象的编码方式得到的,就应该使用单例模式,或者不是面向对象的,但它本身的属性应该是面向对象的,虽然使用静态方法能同样解决问题,但是最好的解决方案也应该是使用单例模式。

从功能上讲:
单例模式可以控制单例数量;可以进行有意义的派生;对实例的创建有更自由的控制。

3️⃣数据库连接能不能做 Singleton?

如果是简单地把一个 connection 对象封存在单例对象中,这样是错误的。因为连接池里有多个链接可以用,如果使用 Singleton,那在 WEB 访问时,就只能用一个数据库链接,那不是死的很惨?

但是链接池可以使用单例模式,初始化的时候创建比如 100 个 connection 对象,然后在需要的时候提供一个,用过之后返回到 pool 中。用单例模式,是保证连接池有且只有一个。

再举个例子,比如 DAO 层写好一个调用数据库表的类,在 Service 层应用此类时,如果每次都 new 创建的话需要频繁的创建和回收,而 DAO 层这个类里又没有和对象相关的值变量,所以不需要每次都 new 一个,此时就可以用单例模式来创建这个 DAO 实例。

【AIGC】大模型面试高频考点09-大模型Agent框架 聚焦AIGC专业技术分享 阅读详情

相关推荐

永磁同步电机自抗扰控制ADRC(位置环/速度环控制器)Matlab/Simulink仿真(S-Function)

ESO是ADRC的核心,其作用是跟踪被控对象的输出,同时给出受控对象的各阶状态变量以及系统总扰动的实时估计,将其补偿到控制器中,实现动态补偿线性化。NLSEF采用非线性函数把TD产生的跟踪及微分信号与ESO给出的状态变量估计值之间的误差进行非线性组合得到初级控制量,然后同总扰动的补偿量一起生成最终的控制信号。自抗扰控制(ADRC)技术的核心思想是将简单的积分串联型视为标准模型,把系统模型中不同于标准型的部分和外部干扰之和视为总扰动,并将其扩张为一个新的状态。看作系统内外部扰动之和。令一个高阶状态变量为。

m0_66341377的博客 7612

静态方法注入bean失败原因

今天在写redission 的一个工具类的时候,随手写出下面的代码 package com.wt.redission.wtredission.utils; import org.redisson.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstr

qq_38071342的博客 1595

Java课程设计——扫雷游戏程序

使用Java语言对扫雷游戏的复刻

m0_60671275的博客 3496

static静态方法工具类中注入bean失败,@Autowired在static方法中注入时失效导致的NullPointerException

static静态方法工具类中注入bean失败,@Autowired注入的对象在static方法中为null,报出空指针。根据SpringBoot启动和Bean注入的时机,各个注解生效时间,对象创建时间先后关系,稍微梳理后得出只能在运行时获取bean,那么答案就是运行中获取bean只能通过上下文对象ApplicationContext

阿韩的经验分享博客 1359

从零开始:手把手教你做转录组与代谢组的联合分析(含R代码)

本文详细介绍了转录组与代谢组联合分析的全流程,包括数据准备、预处理、差异分析及可视化方法,并提供了实用的R代码示例。通过多组学整合分析,研究者可以更全面地理解生物过程,适用于疾病机制和药物开发等医学研究领域。

weixin_29306317的博客 436

立创开源便携式多生理参数监护仪:基于STM32H743与ADS1292R的心电血氧体温监测系统设计

本文详细解析了基于STM32H743与ADS1292R的便携式多生理参数监护仪开源设计。项目集成了心电、血氧和体温监测功能,采用模块化硬件架构,并重点介绍了利用FIR滤波和Pan-Tompkins算法进行心电信号处理的核心技术。文章提供了完整的复刻指南与避坑要点,是学习医疗电子设备设计的优秀实践案例。

weixin_30600615的博客 326

java static spring_static静态方法内调用Spring(依赖注入)的bean

前言:一般需要在static方法里调用注入进来的service,因为是静态方法,所以必须声明该service也必须是static的,这时候你会发现注入不进来,会报null指针,这个时候需要使用@PostConstruct来解决。第一种Spring也基于JSR-250注解,包括@PostConstruct,@PreDestroy和@Resource注解。虽然这些注释都没有真正必需的,因为你已经有...

weixin_35881820的博客 1814

如何设计一个低代码平台

近些年来,低代码发展火热,各种低代码平台如雨后春笋纷纷崛起,这些平台各定位不同,优劣不同,用户的选择空间很大。那么,如果用户想从零开始设计一个低代码平台,该如何做呢?

Jarod_Chou的博客 8256

静态方法中直接使用注入的bean对象

问题:静态方法中注入bean分析问题:先看一段代码 @Componentpublic class ScriptExecuteContent { @Autowired private static SignRepository signRepository; public static String checkSign(String certNo, String acctNo, String i...

weixin_34270606的博客 1052

RT-DETR改进策略【Neck】| GFPN 超越BiFPN 通过跳层连接和跨尺度连接改进RT-DETR颈部网络

本文记录的是利用颈部结构优化RT-DETR的目标检测网络模型。利用改进后的颈部网络,通过跳层连接,避免了在进行反向传播时的梯度消失问题,并且引入跨尺度连接,可以实现不同级别和层次的特征充分融合,获取足够的高层语义信息和低层空间信息交换,从而在大规模变化场景下提高检测性能。GIRAFFEDET: A HEAVY-NECK PARADIGM FOR OBJECT DETECTION-GFPN包含了上述的跳层连接(dense-link和log2nlog _{2} nlog2​n-link)以及跨尺度连接(Quee

Limiiiing的博客 2228

【RT-DETR有效改进】为什么YOLO版本的RT-DETR训练模型不收敛精度差的问题

本文的内容同样为本专栏的前期预热文章,文章主要解释一下为什么有的人跑ultralytics仓库的RT-DETR精度很差,模型不收敛,mAP异常的情况。为了验证这一情况我也是跑了多个实验,从多个数据集出发,100-500的数据集我跑了大概5个数据集,1000的我跑了二个,2000的我跑了一个,4000的跑了一个,同时其中一些版本我也用了不同的batch_size来出发验证精度异常的情况。

Snu77的博客 9758

@Autowired注解和静态方法以及new的关系

一、@autowired 与new   new出来的对象无法调用@Autowired注入的Spring Bean,否则报空指针异常, @Autowired注入Spring Bean,则当前类必须也是Spring Bean才能调用它,不能用new xxx()来获得对象,这种方式获得的对象无法调用@Autowired注入的Bean。 二、@autowired 与静态方法 1.spring框架应...

xuhaogang3的博客 3632

执行任务赚积分

接下来N行,每行两个空格分隔的整数(SLA和V),SLA表示任务的最晚处理时间,V表 示任务对应的积分。每个任务都有最晚处理时间限制和积分值,在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。现有N个任务需要处理,同一时间只能处理一个任务,处理每个任务所需要的时间固定为1。可用于处理任务的时间有限,请问在有限的时间内,可获得的最多积分。第2个时间单位内,处理任务4,获得5个积分。输入描述:第一行为一个数N,表示有N个任务,1

面试高手的博客 4694

spring注入时bean的set方法为什么不能是static类型的?

静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法

z69183787的专栏 9496

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

spring注入时bean的set方法为什么不能是static类型的?(为什么要用单例模式而不是静态方法)

态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法 在springframework里,我们不能@Autowired一个静态变量,使之成为一个spring bean,例如下面这样: [java] view plaincopy @Autowired   private static 

争做优秀java技术博客! 2808

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

spring注入时bean的set方法为什么不能是static类型的?

静态方法是属于类(class)的,普通方法才是属于实体对象(也就是New出来的对象)的,spring注入是在容器中实例化对象,所以不能使用静态方法 在springframework里,我们不能@Autowired一个静态变量,使之成为一个spring bean,例如下面这样: [java] @Autowired privatestaticYourClassy...

weixin_34072159的博客 174

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Spring 01:IoC、Bean与依赖注入

从Spring开始重新了解SpringBoot,关于IoC、Bean与依赖注入

dfraetaem的博客 1948

spring @Value注入map、List、Bean、static变量方式及详细使用

使用@Value注入map、List 实体类 List: @Value("${test.list.ids:1,2,3}") private List<String> testList; 或者 @Value("${test.list.ids:1,2,3}") private String[] testList; List 指定分隔符 ...

赵英超的博客 4万+

Spring中static变量不能@value注入的三种解决方法

在写工具类时往往需要用到配置文件的信息,在使用@Value("${}")注入时出现问题,报空指针异常,获取到的值为空,原因是使用了static修饰,具体原因可参见:工具类使用@Autowired无法注入bean的三种解决方法,下面说说解决方法。 第一种,使用@PostConstruct注解 package ts.util; import javax.annotation.PostConst...

hunt_er的博客 4374

Spring静态注入Bean

Spring依赖注入是基于对象的,static是基于类级别的。所以静态注入在使用的时候会抛出java.lang.NullPointerException空指针运行时异常 使用@PostConstruct方式: 1.对工具类使用@Component 注解 2.@Autowired 注解注入bean 3.@PostConstruct 使用该注解定义init()方法,在方法中给当前对象赋值 ...

程序员 2860

Spring静态工具类中注入 Bean 的原理与实现

静态工具类不能直接向 static 字段注入 Bean,真正原因是 Spring 的标准依赖注入面向 Bean 实例,而不是 ApplicationContext 无法注入。本文通过 ApplicationContextAware 将容器引用桥接到静态上下文,分析 Aware 回调、resolvableDependencies 与 getBean 的实际机制,并说明该方案适合兼容既有静态调用,新代码仍应优先使用构造器注入。

Mr__Miss的博客 227

spring注入static属性

(@PreDestroy 注解定义容器销毁之前的所做的操作)这种方式和在xml中配置 init-method和 destory-method方法差不多,定义spring 容器在初始化bean 和容器销毁之前的所做的操作;通过MethodInvokingFactoryBean工厂Bean,可以将指定方法返回值注入成为目标Bean的属性值,MethodInvokingFactoryBean用来获得指定方法的返回值,该方法可以是静态方法 也可以是实例方法。工具类一般都是静态方法,静态方法只能访问静态属性。

2509_94228653的博客 425

static静态类获取bean方法

工具类的某个方法想要获取bean的实例,但是工具类的方法是static的,不能使用@Autowired 注入,这个时候需要重写 SpringContextHolder; @Slf4j public class SpringContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 获取applicationCo

eternity_zzy的博客 2704

springboot如何在static方法中使用自动注入的属性

第一步:写注解@Component 使当前类成为一个bean对象。(@Controller,@service都行) 第二步:写个static的变量 第三步:写个@PostConstruct注解注解注释的方法,在这个方法里,将自动注入的值赋值给定义的static变量 第四步:static变量替代自动注入在static方法里面使用 复制代码 @Component public class DSHWec...

weixin_43694038的博客 2744
上一篇: Oracle 的 start with ... connect by prior ...
下一篇: 自定义注解@interface
JFS_Study
博客等级 码龄6年 363粉丝 359原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值