【Java面试】第八天

在这里插入图片描述

🌟个人主页:时间会证明一切.


目录

  • BeanFactory和FactroyBean的关系?
    • BeanFactory
    • FactoryBean
  • Spring 中的 Bean 是线程安全的吗?
    • 有状态的Bean如何解决线程安全问题
  • Spring 中的 Bean 作用域有哪些?
    • 作用域与循环依赖
    • 自定义作用域

BeanFactory和FactroyBean的关系?

FactoryBean和BeanFactory是Spring中的两个重要的概念。先看一下他们的类定义:

FactoryBean:

package org.springframework.beans.factory;public interface FactoryBean<T> {T getObject() throws Exception;Class<?> getObjectType();boolean isSingleton();
}

BeanFactory:

package org.springframework.beans.factory;public interface BeanFactory {Object getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;boolean containsBean(String name);boolean isSingleton(String name) throws NoSuchBeanDefinitionException;boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// ...
}

至少从代码上来看,这两个东西都是接口(interface),然后都是在org.springframework.beans.factory包下面的。

网上有很多概念的解释,说明他俩的区别,但是很多人还是看不懂,下面是的解释我结合了具体的case,帮助大家更好地理解他们的作用,理解了各自的作用,那么区别自然也就理解了。

BeanFactory

BeanFactory比较常用,名字也比较容易理解,就是Bean工厂,他是整个Spring IoC容器的一部分,负责管理Bean的创建和生命周期。

其中提供了一系列方法,可以让我们获取到具体的Bean实例。你可能没有直接用过BeanFactory,但是你肯定用过或者见过:

applicationContext.getBean(requiredType);applicationContext.getBean(name);

以上就是我们经常用的,在Spring的上下文中通过bean名称或者类型获取bean的方式,而这里的ApplicationContext,其实就是一种BeanFactory。这里面调用的getBean方法,就是上面我们在BeanFactory中看到的方法。

所以,BeanFactory是Spring IoC容器的一个接口,用来获取Bean以及管理Bean的依赖注入和生命周期。

FactoryBean

FactoryBean是一个接口,用于定义一个工厂Bean,它可以产生某种类型的对象。当在Spring配置文件中定义一个Bean时,如果这个Bean实现了FactoryBean接口,那么Spring容器不直接返回这个Bean实例,而是返回FactoryBean#getObject()方法所返回的对象。

是不是还是听不懂?

那我给你举个具体的例子你就知道了。

Dubbo用过吧(没用过?那可能理解起来比较吃力,因为FactoryBean确实是在很多框架中用到的比较多,比如Kafka、dubbo等各种框架中都会用他来和Spring做集成)。

当我们想要在Dubbo中定义一个远程的提供者提供的的Bean的时候,可以用@DubboReference或者dubbo:reference

这两种定义方式的最终实现都是一个Dubbo中的ReferenceBean ,它负责创建并管理远程服务代理对象。而这个ReferenceBean就是一个FactoryBean的实现。

public class ReferenceBean<T> implements FactoryBean<T>,ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {}

ReferenceBean的主要作用是创建并配置Dubbo服务的代理对象。这些代理对象允许客户端像调用本地方法一样调用远程服务。创建Dubbo服务代理通常涉及复杂的配置和初始化过程,包括网络通信设置、序列化配置等。通过ReferenceBean将这些复杂性封装起来,对于使用者来说,只需要通过简单的Spring配置即可使用服务。

ReferenceBean 实现了 FactoryBean 接口并实现了getObject方法。在getObject()方法中,ReferenceBean会给要调用的服务创建一个动态代理对象。这个代理对象负责与远程服务进行通信,封装了网络调用的细节,使得远程方法调用对于开发者来说是透明的。

通过 FactoryBean 实现,ReferenceBean 还可以延迟创建代理对象直到真正需要时,这样可以提升启动速度并减少资源消耗。此外,它还可以实现更复杂的加载策略和优化。

通过实现 FactoryBean,ReferenceBean 能够很好地与Spring框架集成。这意味着它可以利用Spring的依赖注入,生命周期管理等特性,并且能够被Spring容器所管理。

所以,FactoryBean通常用于创建很复杂的对象,比如需要通过某种特定的创建过程才能得到的对象。例如,创建与JNDI资源的连接或与代理对象的创建。就如我们的Dubbo中的ReferenceBean。

Spring 中的 Bean 是线程安全的吗?

Spring的Bean是否线程安全,这个要取决于他的作用域。Spring的Bean有多种作用域,其中用的比较多的就是Singleton和Prototype。

默认情况下,Spring Bean 是单例的(Singleton)。这意味着在整个 Spring 容器中只存在一个 Bean 实例。如果将 Bean 的作用域设置为原型的(Prototype) ,那么每次从容器中获取 Bean 时都会创建一个新的实例。

对于Prototype这种作用域的Bean,他的Bean 实例不会被多个线程共享,所以不存在线程安全的问题。

但是对于Singleton的Bean,就可能存在线程安全问题了,但是也不绝对,要看这个Bean中是否有共享变量。

如以下Bean:

@Service
public class CounterService {private int count = 0;public int increment() {return ++count;}
}

默认情况下,Spring Bean 是单例的,count字段是一个共享变量,那么如果多个线程同时调用 increment 方法,可能导致计数器的值不正确。那么这段代码就不是线程安全的。

我们通常把上面这种Bean叫做有状态的Bean,有状态的Bean就是非线程安全的,我们需要自己来考虑他的线程安全性问题。

那如果一个Singleton的Bean中是无状态的,即没有成员变量,或者成员变量只读不写,那么他就是个线程安全的。

@Service
public class CounterService {public int increment(int a) {return ++a;}
}

所以,总结一下就是:

Prototype的Bean是线程安全的,无状态的Singleton的Bean是线程安全的。有状态的Singleton的Bean是非线程安全的。

有状态的Bean如何解决线程安全问题

想要让一个有状态的Bean变得线程安全,有以下几个做法:

1、修改作用域为Prototype,这样的Bean就可以避免线程安全问题。

@Scope("prototype")
@Service
public class CounterService {private int count = 0;// ...
}

但是需要注意,Prototype的bean,每次从容器中请求一个 Prototype Bean 时,都会创建一个新的实例。这可能导致性能开销,特别是在需要频繁创建对象的情况下。 而且,每个 Prototype Bean 的实例都需要占用一定的内存,可能会导致内存资源的消耗较大。

2、加锁

想要实现线程安全,有一个有效的办法就是加锁,在并发修改共享变量的地方加锁:

@Service
public class CounterService {private int count = 0;public synchronized int increment() {return ++count;}
}

但是加锁的话会影响并发,降低系统的吞吐量,所以使用的时候需要谨慎,不建议用这个方案。

3、使用并发工具类

可以使用并发包中提供的工具类,如原子类,线程安全的集合等。

import java.util.concurrent.atomic.AtomicInteger;public class CounterService {private AtomicInteger count = new AtomicInteger(0);public int increment() {return count.incrementAndGet();}
}

建议使用这种,既能保证线程安全,又有比较好的性能。

Spring 中的 Bean 作用域有哪些?

所谓作用域,其实就是说这个东西哪个范围内可以被使用。如我们定义类的成员变量的时候使用的public、private等这些也是作用域的概念。

Spring的Bean的作用域,描述的就是这个Bean在哪个范围内可以被使用。不同的作用域决定了了 Bean 的创建、管理和销毁的方式。

常见的作用域有Singleton、Prototype、Request、Session、Application这五种。我们在代码中,可以在定义一个Bean的时候,通过@Scope 注解来指定他的作用域:

@Service
@Scope("prototype")
public class HollisTestService{}

这五种作用域的解释如下:

  1. 单例(Singleton)
    • 默认作用域。
    • 对于每个 Spring IoC 容器,只创建一个 Bean 实例。
    • 适用于全局共享的状态。
  2. 原型(Prototype)
    • 每次请求都会创建一个新的 Bean 实例。
    • 适用于所有状态都是非共享的情况。
  3. 请求(Request)
    • 仅在 Web 应用程序中有效。
    • 每个 HTTP 请求都会创建一个新的 Bean 实例。
    • 用于请求级别的数据存储和处理。
  4. 会话(Session)
    • 仅在 Web 应用程序中有效。
    • 每个 HTTP 会话都会创建一个新的 Bean 实例。
    • 适用于会话级别的数据存储和处理。
  5. 应用(Application)
    • 仅在 Web 应用程序中有效。
    • 在 ServletContext 的生命周期内,只创建一个 Bean 实例。
    • 适用于全应用程序级别的共享数据。
  6. Websocket
    • 仅在 Web 应用程序中有效。
    • 在 Websocket 的生命周期内,只创建一个 Bean 实例。
    • 适用于websocket级别的共享数据。

一般来说我们都是使用Singleton的作用域,有的时候也会用Prototype,其他几个用得不多。

以下两张图是Spring官方给的关于singleton和prototype的区别。其实就是会创建一个Bean还是多个Bean的区别:

singleton.png

prototype.png

作用域与循环依赖

Spring在解决循环依赖时,只解决了单例作用域的,别的作用域没有解决:

自定义作用域

除了Spring官方提供的这些作用域以外,我们还可以自定义我们自己的作用域,Spring提供了这方面的支持。

要自定义一个 Spring 的作用域,需要实现 org.springframework.beans.factory.config.Scope 接口。这个接口要求实现几个关键方法来管理 Bean 的生命周期。

public interface Scope {Object get(String name, ObjectFactory<?> objectFactory);@NullableObject remove(String name);void registerDestructionCallback(String name, Runnable callback);@NullableObject resolveContextualObject(String key);@NullableString getConversationId();
}

接下来,我们需要实现接口的方法,例如 get(创建或检索 Bean 实例)、remove(销毁 Bean 实例)等。

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;public class MyCustomScope implements Scope {@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {// 实现获取 Bean 的逻辑return objectFactory.getObject();}@Overridepublic Object remove(String name) {// 实现移除 Bean 的逻辑return null;}@Overridepublic void registerDestructionCallback(String name, Runnable callback) {// 注册 Bean 销毁时的回调}@Overridepublic Object resolveContextualObject(String key) {// 用于解析相关上下文数据return null;}@Overridepublic String getConversationId() {// 返回当前会话的 IDreturn null;}
}

接下来,我们需要 Spring 配置中注册这个自定义的作用域。这可以通过 ConfigurableBeanFactory.registerScope 方法实现。

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic MyCustomScope myCustomScope(ConfigurableBeanFactory beanFactory) {MyCustomScope scope = new MyCustomScope();beanFactory.registerScope("myCustomScope", scope);return scope;}
}

在 Bean 定义中使用自定义的作用域的名称。Spring 容器将会根据你的自定义逻辑来创建和管理这些 Bean。

@Component
@Scope("myCustomScope")
public class MyScopedBean {// ...
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

6.6高斯噪声

在OpenCV联合C中给一张图片添加高斯噪声&#xff08;Gaussian Noise&#xff09;&#xff0c;可以通过生成随机数并在图像的每个像素上加上这些随机数来实现。高斯噪声是一种统计分布服从正态分布的噪声&#xff0c;通常用于模拟自然界的许多物理现象。 示例代码 以下是一个使…

衡石分析平台使用手册-通用配置文档

配置文件​ 配置文件中存放 HENGSHI SENSE 的配置参数&#xff0c;可以通过修改配置文件来改变 HENGSHI SENSE 的服务方式。 配置文件说明​ 配置文件存放在 conf 路径下&#xff0c;包含 hengshi-sense-env.sh 和 engine-segment-hosts 两个文件。其中 engine-segment-host…

R18 Enhancements on CHO procedure for NES cell(s)(NES event)

在 R18 Network energy savings(NES) 之cell DTX/DRX https://t.zsxq.com/o1jnp 中有提到DCI format 2_9中的field NES-mode indication,这个field就与另一个NES feature相关,下面就简单看下。 在TR 38.864中有提到Connected mode mobility的内容:在 NES mode switching期间…

标准库、HAL库、LL库

目录 举例理解 概念理解 标准库&#xff08;Standard Peripheral Library&#xff0c;SPL&#xff09; 2. HAL库&#xff08;Hardware Abstraction Layer&#xff09; 3. LL库&#xff08;Low-Layer Library&#xff09; 总结区别 如何选择 实际应用中的结合使用 代码…

根据第七次人口普查数据探索中国平均预期寿命

一&#xff1a;数据介绍 数据来源&#xff1a;预期寿命数据集 - Heywhale.com 该数据提供了中国各地区在第七次人口普查&#xff08;2020年&#xff09;中的平均预期寿命&#xff0c;包括男性和女性的预期寿命。该表具有93行和3列。以下是关于这个数据表的具体信息&#xff1…

设计师私藏的 PDF 转 JPG 利器

你平常会通过扫描来发送文件吗&#xff1f;为了保证图片的清晰度一般都会采用PDF格式来转发&#xff0c;但是要插入到一些文件里的时候PDF格式不是那么好用。这时候就很需要PDF转jpg工具了。今天我就分享几款我用过的PDF转jpg的工具&#xff0c;有兴趣就接着往下看吧。 1.福昕…

蓝牙模块助力游戏设备开启沉浸式娱乐新体验

在当今科技飞速发展的时代&#xff0c;游戏设备正经历着一场前所未有的智能化变革。作为连接虚拟世界与现实体验的重要桥梁&#xff0c;蓝牙模块已经成为游戏设备不可或缺的核心组件之一。它的广泛应用&#xff0c;不仅为玩家提供了更加便捷、流畅的游戏体验&#xff0c;更推动…

python制作石头剪刀布

方法一&#xff1a; import random def rock_paper_scissors(): user_score 100 computer_score 100 while user_score > 0 and user_score < 200: user_choice int(input("请输入1&#xff08;剪刀&#xff09;、2&#xff08;石头&#x…

算子级血缘在金融数据环境的实践应用

在企业的数据管理领域&#xff0c;算子级血缘极大优化了脚本内部字段口径的理解与追踪。面对几十、几百乃至几千行代码的复杂脚本&#xff0c;并且有着各种函数调用、数据转换等复杂的加工逻辑&#xff0c;如果通过传统的 ETL 工作模式&#xff0c;开发人员就不得不采用“盲人摸…

PDF——压缩大小的方法

方法一&#xff1a;QQ浏览器->格式转换->PDF转纯图PDF

从“看”到“管”:EasyCVR安防监控平台如何推动城市管理模式的转型升级

在21世纪的今天&#xff0c;随着城市化进程的加速推进&#xff0c;城市规模不断扩大&#xff0c;人口密集度显著增加&#xff0c;城市管理面临着前所未有的挑战。从公共安全、交通管理到环境保护、应急响应&#xff0c;每一个领域都对城市的治理能力和效率提出了更高要求。在这…

【STM32】DMA数据转运(存储器到外设)

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 前言 外设DMA请求使能 DMA1 DMA2 常用的外设DMA使能库函数 配置串口发送的DMA请求 驱动代码 MyDMA.h MyDMA.c main.c 前言 【STM32】DMA数据转运&#xff08;存储器到存储器&a…

c++----模板(进阶)

也是好久没有更新了今天来将我们前面写过的模板更加升华一下。更加深一下。我们还记得我们前面讲过的模板&#xff0c;只是简单的运用模板而且还是参数类型模板。当然大家如果敏锐一点的话&#xff0c;应该就能看出这句话的问题看吧。我这里说的是参数类型模板&#xff0c;那么…

模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性

先看抖音的格式 对ID加密的格式 MB4EENgLILJPeQKhJht-rjcc6y0ECMk_RGTceg6JBAA 需求是 同一个ID 比如 413884936367560 每次获取得到的加密ID都是不同的&#xff0c;最终解密的ID都是413884936367560 注意这是一个加密后可解密原文的方式&#xff0c;不是单向加密 那么如下进行…

Java在零工市场中的应用:构建灵活高效的劳动力平台

随着数字经济的迅猛发展&#xff0c;零工经济作为一种新兴的劳动力市场模式&#xff0c;正在全球范围内迅速崛起。零工市场通过互联网平台将服务提供者与需求者进行快速匹配&#xff0c;使得个人可以临时、自由地提供服务&#xff0c;企业则能够按需雇佣劳动力&#xff0c;实现…

清理微信一些文件

C盘的微信文件实在是太难搞了&#xff0c;怎么弄怎么麻烦 一般文件保存在手机端或者自己的文件夹更多&#xff0c;要清理呀 不然卡秃噜皮了怎么办是啊不 路径如图

【JAVA入门】Day45 - 压缩流 / 解压缩流

【JAVA入门】Day45 - 压缩流 / 解压缩流 文章目录 【JAVA入门】Day45 - 压缩流 / 解压缩流一、解压缩流二、压缩流 在文件传输过程中&#xff0c;文件体积比较大&#xff0c;传输较慢&#xff0c;因此我们发明了一种方法&#xff0c;把文件里的数据压缩到一种压缩文件中&#x…

Linux与Ubuntu:内核与发行版的关系

在计算机科学的领域内&#xff0c;Linux和Ubuntu这两个术语频繁出现&#xff0c;但它们之间的确切联系往往不为大众所熟知。本文旨在深入探讨Linux内核与Ubuntu操作系统发行版之间的技术关系&#xff0c;并阐明它们各自的独特性质。 Linux内核&#xff1a;操作系统的基石 Lin…

双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的实践应用

查看原文>>> 双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的实践技术应用 目录 专题一、DNDC模型介绍 专题二&#xff1a;DNDC初步操作 专题三、遥感和GIS基础 专题四、DNDC气象数据 专题五、DNDC土地数据 专题六…

项目警告Added non-passive event listener to a scroll-blocking ‘touchstart‘ event.

使用touchstart和touchmove时项目报如下警告&#xff1a; 这个警告信息是由浏览器提供的&#xff0c;主要是为了提醒开发者关注性能问题。在移动设备上&#xff0c;touchstart事件可能会导致滚动操作的响应问题。当你在touchstart事件上添加了一个非被动的监听器&#xff08;即…