Spring 面试题(四)

1. Spring 防止相同类型 Bean 注入异常的方法?

在Spring框架中,当存在多个相同类型的Bean时,如果尝试通过自动装配(Autowiring)来注入这些Bean,可能会引发异常,因为Spring不知道应该注入哪一个Bean实例。为了避免这种情况,你可以采取以下几种方法:

  1. 使用@Primary注解
    为其中一个Bean添加@Primary注解,这会让Spring在自动装配时优先考虑这个带有@Primary注解的Bean。如果没有其他明确的指示,Spring会选择这个Bean进行注入。

    @Bean
    @Primary
    public MyService myPrimaryService() {return new MyPrimaryServiceImpl();
    }@Bean
    public MyService myAlternativeService() {return new MyAlternativeServiceImpl();
    }
    
  2. 使用@Qualifier注解
    在注入点使用@Qualifier注解来明确指定要注入的Bean的名称。这允许你精确地控制要注入哪个Bean。

    @Autowired
    public void setMyService(@Qualifier("myAlternativeService") MyService myService) {this.myService = myService;
    }
    
  3. 使用Java配置和条件注解
    通过@Conditional系列的注解,你可以根据特定的条件来决定是否创建某个Bean。这可以帮助你确保在特定的上下文中只有一个合适的Bean被创建。

    @Bean
    @ConditionalOnMissingBean(name = "myAlternativeService")
    public MyService myPrimaryService() {return new MyPrimaryServiceImpl();
    }
    
  4. 使用@Resource注解(JSR-250)
    @Resource注解允许你通过名称进行注入,这是Java标准提供的特性。你可以通过指定Bean的名称来避免歧义。

    @Resource(name = "myAlternativeService")
    private MyService myService;
    
  5. 避免定义多个相同类型的Bean
    如果可能的话,尽量避免定义多个相同类型的Bean。你可以考虑将不同的实现作为同一个Bean的不同配置,或者使用继承和接口来组织你的服务。

  6. 使用构造函数注入
    通过构造函数注入可以减少歧义,因为每个构造函数参数都需要明确指定。如果构造函数需要多个相同类型的参数,你可以通过不同的参数名称或类型来区分它们。

  7. 配置文件中显式定义
    如果你使用基于XML的配置,你可以在配置文件中显式指定Bean之间的依赖关系,避免自动装配时的歧义。

    <bean id="myBean" class="com.example.MyBean"><property name="myService" ref="myAlternativeService"/>
    </bean>
    
  8. 自定义自动装配解析器
    如果上述方法都不适用,你可以考虑实现自定义的自动装配解析器,根据特定的逻辑来解析和注入Bean。这通常是一个高级特性,需要深入理解Spring框架的内部机制。

2. Spring 如何在 Bean 初始化时进行操作?

在Spring框架中,可以通过多种方式在Bean初始化时进行操作。以下是一些常用的方法:

  1. 实现 InitializingBean 接口

Spring框架提供了一个名为InitializingBean的接口,该接口包含一个方法afterPropertiesSet()。如果你希望Bean在初始化属性设置后执行一些操作,可以实现这个接口并覆盖该方法。

public class MyBean implements InitializingBean {// 其他属性和方法@Overridepublic void afterPropertiesSet() throws Exception {// 初始化后的操作}
}
  1. 指定 init-method

在Spring的XML配置文件中,可以为<bean>元素指定一个init-method属性。这个属性指定的方法会在Bean的所有属性设置完成之后执行。

<bean id="myBean" class="com.example.MyBean" init-method="init"/>

然后在Bean类中定义这个方法:

public class MyBean {// 其他属性和方法public void init() {// 初始化操作}
}
  1. 使用 @PostConstruct 注解

如果你使用注解来配置Bean,可以使用@PostConstruct注解来标记一个方法,这个方法会在依赖注入完成后执行。这通常用于Java EE环境,但Spring也支持这个注解。

import javax.annotation.PostConstruct;public class MyBean {// 其他属性和方法@PostConstructpublic void init() {// 初始化操作}
}
  1. 利用 BeanPostProcessor

BeanPostProcessor是一个强大的接口,它允许你在Bean初始化之前和之后执行自定义逻辑。通过实现这个接口,并覆盖postProcessAfterInitialization方法,你可以对所有Bean的初始化过程进行干预。

public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 初始化后的操作return bean;}
}

然后,在Spring配置中注册这个BeanPostProcessor。

<bean class="com.example.MyBeanPostProcessor"/>
  1. 利用 @EventListener 注解

在Spring 4.2及以后的版本中,你可以使用@EventListener注解来监听Spring容器的事件。例如,你可以监听ContextRefreshedEvent事件,这个事件在Spring容器初始化完成后触发。

import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class MyEventListener {@EventListenerpublic void handleContextRefreshedEvent(ContextRefreshedEvent event) {// 容器初始化完成后的操作}
}

通常,对于简单的初始化逻辑,使用@PostConstruct注解或init-method属性就足够了。然而,如果你需要更复杂的逻辑,比如基于Bean类型的条件性初始化,那么BeanPostProcessor可能是一个更好的选择。使用@EventListener监听容器事件的方式则适用于需要在容器完全初始化后进行操作的场景。

3. Spring 如何在 Bean 销毁时进行操作?

在Spring框架中,如果你想在Bean销毁时执行一些操作,可以通过实现DisposableBean接口或使用@PreDestroy注解来实现。这些方法主要用于执行清理操作,如关闭资源、断开连接等。

以下是两种方法的示例:

方法一:实现DisposableBean接口

你可以让你的Bean类实现DisposableBean接口,并覆盖destroy()方法。当Spring容器关闭时,会调用所有实现了DisposableBean接口的Bean的destroy()方法。

import org.springframework.beans.factory.DisposableBean;public class MyBean implements DisposableBean {@Overridepublic void destroy() throws Exception {// 执行清理操作System.out.println("MyBean is being destroyed.");// 例如关闭资源、断开数据库连接等}
}

方法二:使用@PreDestroy注解

@PreDestroy注解是JSR-250规范的一部分,它标注的方法会在Bean销毁之前被调用。你需要在类上定义一个方法,并在该方法上使用@PreDestroy注解。

import javax.annotation.PreDestroy;public class MyBean {@PreDestroypublic void cleanup() {// 执行清理操作System.out.println("MyBean is being destroyed with @PreDestroy.");// 例如关闭资源、断开数据库连接等}
}

注意,为了使用@PreDestroy注解,你需要确保Spring容器能够扫描到它。这通常通过Java配置(使用@ComponentScan注解)或XML配置(使用<context:component-scan>元素)来实现。

此外,如果你的Bean是通过Java配置来定义的,你还可以直接在@Bean方法上使用@PreDestroy注解,而不是在Bean类内部。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PreDestroy;@Configuration
public class AppConfig {@Beanpublic MyBean myBean() {return new MyBean();}@PreDestroypublic void destroyMyBean() {// 执行清理操作,针对myBean()方法返回的Bean实例System.out.println("Destroying the bean created by myBean() method.");}
}

在这种情况下,destroyMyBean()方法会在myBean()方法返回的Bean实例销毁之前被调用。

记住,@PreDestroy注解的方法不会被调用,除非Bean是通过Spring容器管理的,并且Spring容器正在正常关闭。如果你直接通过new关键字创建Bean实例,那么这些方法将不会被执行。此外,如果你的应用程序是通过异常或强制终止而关闭的,Spring可能无法确保所有的@PreDestroy方法都被调用。

4. Spring 中 @Component, @Service, @Repository, @Controller 的区别是什么?

在Spring框架中,@Component@Service@Repository@Controller都是用于标识Bean的注解,但它们各自具有特定的用途和场景。以下是这些注解之间的主要区别:

  1. @Component

    • @Component是Spring框架中的一个通用注解,用于标识一个类作为组件,使其能够被Spring容器管理。
    • 它可以用于任何类,将其标记为Spring容器中的Bean,从而可以通过依赖注入(DI)机制来管理和使用这些组件。
    • @Component是这四个注解中最通用和基础的,其他三个注解(@Service@Repository@Controller)实际上都可以看作是@Component的特殊形式或扩展。
  2. @Service

    • @Service注解通常用于标识业务逻辑层的组件,即服务类。
    • 在Spring中,服务类通常包含业务逻辑的实现,并且可能会被多个控制器或其他服务所调用。
    • @Service注解是@Component的一个特殊形式,它增加了对服务类这一特定角色的语义化标识。
  3. @Repository

    • @Repository注解用于标识数据访问对象(DAO),即与数据库进行交互的类。
    • 它不仅将类标记为Spring容器中的Bean,还提供了将DAO层抛出的数据访问异常转换为Spring的统一数据访问异常的功能,从而方便在业务层进行异常处理。
    • @Repository也是@Component的一个特殊形式,它增加了对数据访问层这一特定角色的语义化标识。
  4. @Controller

    • @Controller注解用于标识Spring MVC框架中的控制器组件。
    • 控制器负责处理用户请求,并返回视图或数据响应。
    • 在Spring MVC中,@Controller注解的类通常与视图解析器一起工作,将请求映射到特定的处理方法,并返回相应的视图或数据。
    • 与其他注解不同,@Controller是专门针对Web层的注解,它提供了与Web请求处理相关的额外功能。

5. Spring 中的 @Bean 与 @Component 注解的区别有哪些?

在Spring框架中,@Bean@Component注解都用于标识和管理Bean,但它们在使用方式和目的上有一些明显的区别。

  1. 使用方式和位置

    • @Component是一个类级别的注解,用于标识一个类作为组件被Spring管理。Spring会自动扫描到带有此注解的类,并将其实例化为Bean,纳入Spring容器的管理。
    • @Bean通常用于配置类(被@Configuration注解标记的类)中的方法上。这些方法被称为Bean定义方法,它们负责创建特定类型的Bean实例。@Bean注解告诉Spring,当需要获取该Bean时,应调用对应的Bean定义方法来创建Bean的实例,并将其纳入Spring容器中。
  2. 控制权

    • 使用@Component注解的类是由Spring框架来统一管理和创建的。
    • @Bean注解允许开发人员手动控制Bean的创建和配置,提供了更大的灵活性。
  3. 自动装配和依赖注入

    • 使用@Component注解的类,Spring会自动进行扫描和实例化,并通过依赖注入(DI)机制来管理这些组件。
    • @Bean注解的方法返回的Bean对象也可以被自动装配到其他需要它的地方,但它更注重于通过方法定义Bean的创建过程。
  4. 目的和用途

    • @Component是一个通用的注解,可以用于标识任何类,使其成为Spring容器中可被自动扫描和实例化的Bean。
    • @Bean注解则更侧重于在配置类中声明和配置Bean对象,提供了更精细化的控制和管理。

6. Spring 中的 @Bean 与 @Component 注解用在同一个类上,会怎么样? 容器中Bean的数量?

在Spring框架中,@Bean@Component注解有不同的用途和场景,但它们都可以用于创建和管理Bean。如果在一个类上同时使用@Bean@Component注解,可能会导致一些混淆和潜在的问题。

首先,让我们明确这两个注解的用途:

  • @Component:这个注解告诉Spring,这个类是一个组件,Spring应该自动检测并把它作为Bean放入Spring容器中。使用@Component注解的类,其实例化是通过Spring容器自动完成的,遵循Spring的依赖注入和管理规则。

  • @Bean:这个注解通常用在方法上,表明该方法会返回一个对象,这个对象应该被注册为Spring容器中的Bean。@Bean注解的方法通常定义在配置类中(即带有@Configuration注解的类),并且由Spring容器调用以创建Bean实例。

如果在一个类上同时使用这两个注解,可能会出现以下问题:

  1. Bean数量问题:理论上,使用@Component注解的类会作为一个Bean实例被Spring容器管理。而@Bean注解通常用于方法上,表明该方法返回的对象应该被注册为Bean。如果在一个类上同时使用这两个注解,并且没有额外的配置来覆盖或改变这种行为,那么理论上你将在Spring容器中拥有两个Bean实例:一个是由@Component注解自动检测的,另一个是由@Bean方法定义的。

  2. 冲突和混淆:在同一个类上使用这两个注解可能会导致混淆和潜在的冲突。Spring容器可能会尝试创建两个相同的Bean实例,这可能会导致意外的行为或错误。

  3. 覆盖问题:在Spring Boot中,可以通过spring.main.allow-bean-definition-overriding属性来控制是否允许Bean覆盖。如果允许覆盖,并且两个Bean具有相同的名称,那么最终哪个Bean会被使用将取决于Spring容器的初始化顺序。

为了避免混淆和潜在的问题,通常不建议在同一个类上同时使用@Bean@Component注解。你应该根据你的需求选择使用其中一个注解。如果你需要在配置类中定义一个Bean,那么使用@Bean注解在方法上。如果你想要自动检测并注册一个类作为Bean,那么使用@Component(或它的特化注解如@Service@Repository@Controller)注解在类上。

7. Spring 中的 @Autowired 注解的作用?

在Spring框架中,@Autowired注解用于自动装配(依赖注入)Bean对象。具体来说,它能够实现Spring的依赖注入功能,自动将对象的依赖项(也称为Bean)注入到需要的地方,从而消除了显式的依赖关系创建。

@Autowired注解可以应用于成员变量、方法和构造函数上。当应用于成员变量时,Spring容器会自动查找并装配与该变量类型匹配的Bean。同样,当应用于方法或构造函数时,Spring容器会自动为方法的参数或构造函数的参数注入匹配的Bean。

使用@Autowired注解的优点包括:

  1. 简化代码:不再需要手动创建和装配Bean对象,Spring会自动完成这些工作。
  2. 降低耦合度:依赖项由Spring容器负责管理,对象之间的关系更加松散,提高了代码的可维护性和可测试性。
  3. 提高可维护性:通过依赖注入,代码更易于维护和扩展,因为依赖关系被外部化并由Spring容器管理。

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

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

相关文章

ubuntu maven 使用示例

ubuntu maven 使用示例 一、基本使用 1、安装 sudo apt update sudo apt install maven mvn -v2、创建项目 mvn archetype:generate -DgroupIdcom.example -DartifactIdmy-project -DarchetypeArtifactIdmaven-archetype-quickstart -DinteractiveModefalse # -DartifactId…

Java代码基础算法练习-统计学生成绩-2024.04.11

任务描述&#xff1a; 编写程序&#xff0c;输入n个(0<n<50)学生的成绩(输入-1结束)&#xff0c;要求统计并输出优秀(大任务描述:于85)、及格(60~84)和不及格(小于60)的学生人数。(成绩取值范围0~100) 任务要求&#xff1a; 代码示例&#xff1a; /*** 这个程序用于统计…

android 11修改通知栏电池信息的字体颜色

如图为红色。 对应文件为BatteryMeterView loadPercentView之后执行&#xff1a; mBatteryPercentView.setTextColor(Color.RED);

Rust中的Hello World示例程序

开始学习一门新的编程语言就像是迈出了进入全新世界的第一步。你会做的第一件事之一就是编写一个简单的程序&#xff0c;打印出"Hello World!"。 Rust 以其快速和安全而闻名&#xff0c;也不例外。让我们马上开始&#xff0c;一起创建我们的第一个 Rust 程序吧&…

缓存穿透、缓存雪崩、缓存击穿的区别

缓存三兄弟&#xff08;穿透、雪崩、击穿&#xff09; 缓存穿透 定义 查询一个redis和数据库都不存在的值&#xff0c;数据库不存在则不会将数据写入缓存&#xff0c;所以这些请求每次都达到数据库。 解决办法是缓存空对象&#xff0c;如果数据库不存在则将空对象存入缓存&…

分布式锁内容

5.4 分布式锁-redission锁重试和WatchDog机制 说明&#xff1a;由于课程中已经说明了有关tryLock的源码解析以及其看门狗原理&#xff0c;所以笔者在这里给大家分析lock()方法的源码解析&#xff0c;希望大家在学习过程中&#xff0c;能够掌握更多的知识 抢锁过程中&#xff…

【SpringBoot】SpringBoot项目快速搭建

本文将介绍Springboot项目的快速搭建 快速创建SpringBoot项目 打开IDEA在File->New->Project中新建项目 点击左侧的Spring Initializr 输入以下信息&#xff1a; Name 项目名称Group 根据公司域名来&#xff0c;或者默认com.example【倒序域名】Package Name 包名&am…

SpringCloudAlibaba-整合sleuth和zipkin(六)

目录地址&#xff1a; SpringCloudAlibaba整合-CSDN博客 一、整合sleuth 1.引入依赖 在需要追踪的微服务中引入依赖&#xff0c;user、order、product <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter…

数字档案馆升级改造的意义

数字档案馆升级改造的意义在于提升档案管理的效率和质量&#xff0c;更好地满足各方面的需求&#xff0c;并为数字时代的档案管理提供更好的支持和保障。具体意义包括&#xff1a; 1. 提高档案存储、检索和利用效率&#xff1a;玖拓智能数字化档案馆可以实现电子存储和快速检索…

前端vue2中的excel导出功能-file-saver,xlsx,xlsx-style的使用

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 今天遇到了一个技术点.前端的excel的纯导出功能,不和后端交互,只用前端导出数据 整体架构流程 vue2 element-ui 技术名词解释 在网上看了很多帖子,最后我选择了xlsx , file-saver , xlsx-style 这个三个插件完成…

前端项目部署教程——有域名有证书

一、拉取nginx镜像 docker pull nginx //先拉取nginx镜像二、打包前端项目 1、将Vue打包项目传输到/usr/local/vue/下blog和admin文件夹下 重点: 每一个子域名都要申请证书&#xff0c;在阿里云每年可以免费申请20个证书&#xff0c; 免费证书申请教程在 免费证书申请教程 …

ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token

前言 JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在网络上以 JSON 对象的形式安全地传输信息。 JWT 通常用于在用户和服务器之间传递身份验证信息&#xff0c;以便在用户进行跨域访问时进行身份验证。 JWT 由…

spring事务问题的解决和处理

在Spring中&#xff0c;事务管理是通过Transactional注解来实现的。使用Transactional注解可以将一个方法设置成一个事务方法&#xff0c;当方法执行时&#xff0c;会自动开启一个事务&#xff0c;并根据方法执行的结果来决定是提交事务还是回滚事务。 要使用事务&#xff0c;…

day7:哈希表学习

● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和 总结 对于查&#xff0c;某个元素是否在集合中出现过&#xff0c;哈希法是非常高效的方法 但是对于需要去重的情况下&#xff0c;哈希法要注意太多细节&#xff0c;很难完美写完&#xff0c;因此采用双指针…

C语言强制类型转换

目录 王道ppt总结&#xff1a; ​编辑相关博主文章&#xff1a; 王道ppt总结&#xff1a; 相关博主文章&#xff1a;char范围详解&#xff0c;为什么是-128~127,以及int类型范围详解&#xff08;整型数据在内存中的存储&#xff09;_char型和int型数据范围-CSDN博客https://b…

更改el-cascade默认的value和label的键值

后端返回的树结构中&#xff0c;label的key不是el-cascade默认的label&#xff0c;我需要改成对应的字段&#xff0c;但是一直没有成功&#xff0c;我也在文档中找到了说明&#xff0c;但是我没注意这是在props中改&#xff0c;导致一直不成功 这是我一开始错误的写法&#xf…

手把手学爬虫第三弹——爬取动态渲染的信息,2024年最新2024最新阿里Python高级面试题及答案

print(response.json()) except: pass if name ‘main’: url ‘https://ys.mihoyo.com/content/ysCn/getContentList?pageSize20&pageNum1&orderasc&channelId150’ get_data(url) 4.清洗数据 对于返回的JSON格式的数据我们不需要任何选择器就可以直接获…

Qt中的网络通信

C没有封装专门的网络套接字的类&#xff0c;因此C只能调用C对应的API&#xff0c;而在Linux和Windows环境下的API都是不一样的 Qt作为一个C框架提供了相关封装好的套接字通信类 在Qt中需要用到两个类&#xff0c;两个类都属于network且都是属于IO操作&#xff0c;只不过这两个类…

Day:006(2 ) | Python爬虫:高效数据抓取的编程技术(爬虫工具)

selenium 层级定位 窗口的定位&#xff1a; 对于一个现代的web应用&#xff0c;经常会出现框架&#xff08;frame&#xff09; 或窗口&#xff08;window&#xff09;的应用&#xff0c;这也就给我们的定位带来了一个难题。 有时候我们定位一个元素&#xff0c;定位器没有问…

第3章 存储系统(2)

3.3 主存储器与CPU连接 3.3.1 连接原理 现代计算机的MAR和MDR都在CPU内部。 (1)主存储器通过数据总线,地址总线,控制总线与CPU连接。 (2)数据传输率数据总线宽度*总线频率。 (4)控制总线(读写线)控制读写操作。 3.3.2 主存的扩展 数据总线宽度等于存储字长 1.位扩展法【增加…