【Spring面试】五、Bean扩展、JavaConfig、@Import

文章目录

  • Q1、如何在Spring创建完所有的Bean之后做扩展?
  • Q2、Spring容器启动时,为什么先加载BeanFactoryPostProcess?
  • Q3、Bean的生产顺序是由什么决定的?
  • Q4、Spring有哪几种配置方式
  • Q5、JavaConfig是如何替代spring.xml的?
  • Q6、@Component、@Controller、@Service、@Repository有何区别?
  • Q7、@Import可以有几种用法?

Q1、如何在Spring创建完所有的Bean之后做扩展?

问题涉及的源码分析:

点下Download Sources,把源码注释下载进来。new Spring容器时,调用了refresh方法:

在这里插入图片描述

refresh方法:(IoC容器的加载,就是在refresh方法里实现的)

在这里插入图片描述

new ApplicationContext() --> refresh() --> finishBeanFactorylnitialization (循环所有的BeanDefinition ,通过BeanFactory.getBean()生成所有的Bean), 这个循环结束之后所有的bean也就创建完了。而在循环结束后,还有一段代码,就是扩展的关键:

在这里插入图片描述

即这个实例实现了SmartInitializingSingleton接口,这就是实现的扩展点之一。再看refresh源码,finishBeanFactorylnitialization下面还有个finishRefresh方法:

在这里插入图片描述
这里发布了一个ContextRefreshedEvent的事件,我们只要创建个监听器,监听这个事件,也可以完成扩展。

答案:

  • 方式一:实现SmartInitializingSingleton接口

在这里插入图片描述

  • 方式二:要创建个监听器,监听ContextRefreshedEvent事件

在这里插入图片描述

看下效果,以上即Bean加载完成后输出一句测试的话:

在这里插入图片描述

Q2、Spring容器启动时,为什么先加载BeanFactoryPostProcess?

答案:

  • 因为BeanDefinition会在IoC容器加载的时候先注册,而BeanFactoryPostProcess是所有BeanDefinition注册完后做扩展用的,所以要先加载
  • 其次,Ioc容器的加载,即创建Bean,这就需要解析配置类(xml的bean标签、@Component…),负责解析的类也实现了BeanFactoryPostProcessor

在这里插入图片描述

Q3、Bean的生产顺序是由什么决定的?

BeanDefinition里装着Bean的一些信息,看创建IoC容器的源码中的refresh方法的源码:

在这里插入图片描述

答案:

所以Bean的生产顺序是由BeanDefinition的注册顺序决定的,当然依赖关系也会影响Bean的创建顺序。

BeanDefinition的注册顺序由什么决定?

主要由注解(或配置)的解析顺序来决定,由源码看到解析顺序为:

  • @Configuration
  • @Component(当然它还有@Order来细分,这里不细分)
  • @Import的一类
  • @Bean
  • 使用BeanDefinitionRegistryPostProcessor注册的

从上下文拿一下BeanDefinitionNames,是个String[],有序,输出下:

在这里插入图片描述

在这里插入图片描述

按照上面这个注册顺序,以及Spring中后面的Bean覆盖前面的Bean,还可以这么应用:有个用@Component注册的Bean,我想让他失效并替换成另一个,则可以用@Bean再写一个

Q4、Spring有哪几种配置方式

答案:

有三种方式给Spring容器提供配置的元数据:

  • XML配置文件:从Spring诞生开始用,spring.xml中用<bean>标签
  • 基于注解:从Spring2.5+开始,spring.xml <component-scan base-package=""/> + @Component
  • 基于JavaConfig:从Spring3.0开始,使用@Configuration代替xml,使用@Bean代替Bean标签

Q5、JavaConfig是如何替代spring.xml的?

答案:

对于XML

  • 创建Spring容器是new ClassPathXmlApplicationContext(“a.xml”)
  • 有一个spring.xml文件
  • 配置一个Bean是用bean标签,scope、lazy属性
  • 扫描包用<component-scan base-package=""/>
  • 引入外部的属性配置文件用<property-placeHolder resource="/xx.properties">
  • 引入配置文件后,使用其属性给Bean属性赋值为${}
<property name="password" value="${mysql.password}"></property>
  • 指定其他配置文件用<import resource="">

对于JavaConfig

  • 创建Spring容器是new AnnotationConfigApplicationContext(javaConfig.class)
  • 有一个配置类,被@Configuration注解修饰
  • 配置一个Bean是用@Bean注解,属性也用注解@Scope、@Lazy
  • 扫描包用@ComponentScan
  • 引入外部的属性配置文件用@PropertySource("classpath:db.properties")
  • 使用配置文件中的值为@Value("${}")
  • 指定其他用@Import(配置类)

以上是应用层的区别,最后,从源码和流程上来说:大方向都是创建Spring容器(同一个接口,不同的实现类),然后加载、解析配置,再注册为BeanDefinition后交给Bean工厂生产。

在这里插入图片描述

Q6、@Component、@Controller、@Service、@Repository有何区别?

答案:

这四个注解其实是一个注解,@Controller、@Service、@Repository的源注解都是@Component

在这里插入图片描述

之所以分为三种,是因为开发一个项目,常使用三层架构,即控制层、业务层、数据返回层,提供这三个注解用于不同层,提高代码的阅读性。

Q7、@Import可以有几种用法?

答案:

四种:

  • 第一种:直接指定类(如果是配置类,就会按照配置类来解析,如果是个普通类,则直接解析成Bean)
@Import(UserMapper.class)
@Import(JavaConfig.class)   //此时,JavaConfig这个配置类中的Bean也会生效
  • 第二种:导入一个实现了ImportSelector这个接口的类,这种方式可以一次性注册多个,返回一个String[ ],每一个值是完整类路径
public class MyImportSelector implements ImportSelector{@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata){//可以以字符串数组的形式注册多个Bean //字符串必须是类的完整类名return new String[]{"com.llg.UserMapper","com.llg.Role"};}
}
@Configuration
@Import(MyImportSelector.class)
public class MainConfig{}

但注意,这个时候的Bean创建不是正常的IoC加载流程,使用@Import,之前的一个postProcessBeanFactory在所有Beanfinition注册完之后修改这个Import的Bean的信息就会报错

在这里插入图片描述

  • 第三种:导入一个实现ImportBeanDefinitionRegistrar的接口的类,这种也可以一次导入多个,是通过BeanDefinitionRegistry来动态注册BeanDefinition,因此这种方式是没有上面在所有Beanfinition注册完之后修改这个Import的Bean的信息就会报错的这个情况的。

在这里插入图片描述
在这里插入图片描述

  • 第四种:这种其实是第二种的衍生,第二种的接口有个子接口,叫延迟导入选择器,也可以一次导入多个Bean,和ImportSelector的区别是DeferredImportSelector的顺序更靠后

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

SpringMVC基础入门及工作流程---全方面详细介绍

一&#xff0c;SpringMVC概念 Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清晰的几部分&#xff0c;简…

赋能工业物联网 | 数据驱动,加速智能制造

行业背景 工业物联网场景下&#xff0c;随着智能设备及物联网技术的广泛应用&#xff0c;数据是最重要的资源之一&#xff0c;企业需要对各种机器、设备和传感器产生的时序数据进行采集、存储与分析。 因此&#xff0c;何为行之有效的数据库解决方案&#xff1f;企业普遍更为…

MySQL--数据库基础

数据库分类 数据库大体可以分为 关系型数据库 和 非关系型数据库 常用数据类型 数值类型&#xff1a; 分为整型和浮点型&#xff1a; 字符串类型 日期类型

【PTA】浙江大学计算机与软件学院2019年考研复试上机自测

个人学习记录&#xff0c;代码难免不尽人意。 呃&#xff0c;今天做了做19年的复试上机题&#xff0c;死在hash表上了&#xff0c;后面详细解释。心态要好&#xff0c;心态要好 7-1 Conway’s Conjecture John Horton Conway, a British mathematician active in recreational…

SpringMVCJReble的使用文件的上传下载

目录 前言 一、JReble的使用 1.IDea内安装插件 2.激活 3.离线使用 使用JRebel的优势 二、文件上传与下载 1 .导入pom依赖 2.配置文件上传解析器 3.数据表 4.配置文件 5.前端jsp页面 6.controller层 7.测试结果 前言 当涉及到Web应用程序的开发时&…

AI人工智能Mojo语言:AI的新编程语言

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 Mojo的主要功能包括&#xff1a; 类似Python的语法和动态类型使Python开发人员易于学习Mojo&#xff0c;因为Python是现代AI / ML开发背后的主要编程语言。使用Mojo&#xff0c;您可以导入和使用任何Python库&#xf…

设计模式之外观模式

文章目录 影院管理项目传统方式解决影院管理传统方式解决影院管理问题分析外观模式基本介绍外观模式原理类图外观模式解决影院管理传统方式解决影院管理说明外观模式应用实例 外观模式的注意事项和细节 影院管理项目 组建一个家庭影院&#xff1a; DVD 播放器、投影仪、自动屏…

FPGA通信—千兆网(UDP)软件设计

一、PHY引脚功能描述 引脚功能描述1CLK25 CLK125:内部PLL生成的125MHz参考时钟&#xff0c;如MAC未使用125MHe时钟&#xff0c;则此引脚应保持浮动&#xff0c; 2 4 63 GND 接地3REG OUT开关压器&#xff0c;1.05V输出 5 6 8 9 11 12 14 15 MDI[0] MDI[0]- MDI[1] MDI[1…

Redis Redis介绍、安装 - Redis客户端

目录 redis是什么&#xff0c;他的应用场景是什么&#xff1f; Redis的一些主要特点和应用场景&#xff1a; redis的官方网站&#xff1a;Redis redis是键值型数据库&#xff1a;&#xff08;也就是key-value模式&#xff09;&#xff08;跟python的字典很像&#xff09; …

Web server failed to start. Port 8080 was already in use.之解决方法

问题&#xff1a; Web server failed to start. Port 8080 was already in use&#xff0c;这句错误描述意思是当前程序的端口号8080被占用了&#xff0c;需要将占用该端口的程序停止掉才行&#xff1b;错误如图所示&#xff1a; 解决方法&#xff1a; 按住winr&#xff0c;输入…

【大虾送书第九期】速学Linux:系统应用从入门到精通

目录 &#x1f36d;写在前面 &#x1f36d;为什么学习Linux系统 &#x1f36d;Linux系统的应用领域 &#x1f36c;&#xff11;.Linux在服务器的应用 &#x1f36c;&#xff12;.嵌入式Linux的应用 &#x1f36c;&#xff13;.桌面Linux的应用 &#x1f36d;Linux的版本选择 &a…

深入浅出PyTorch函数torch.rand与torch.randn

torch.rand 和 torch.randn 都是PyTorch中用于生成随机张量的函数&#xff0c;但它们生成随机数的方式有所不同。 一、torch.rand torch.rand 生成在区间 [0, 1) 内均匀分布的随机数。 size 参数是一个表示所需张量形状的元组或整数。可以生成任何形状的随机张量。 二、torch.…

C++的运算符重载介绍

所谓重载,就是赋予新的含义。函数重载(Function Overloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作。运算符重载(Operator Overloading)也是一个道理,同一个运算符可以有不同的功能。 实际上,我们已经在不知不觉中使用了运算符重载。例如,+号可以对…

javaee springMVC model的使用

项目结构图 pom依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org…

2020年12月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:数组指定部分逆序重放 将一个数组中的前k项按逆序重新存放。例如,将数组8,6,5,4,1前3项逆序重放得到5,6,8,4,1。 时间限制:1000 内存限制:65536 输入 输入为两行: 第一行两个整数,以空格分隔,分别为数组元素的个数n(1 < n…

[EROOR] SpringMVC之500 回调函数报错

首先&#xff0c;检查一下idea里面的报错的原因&#xff0c;我的是jdk的版本的问题。所以更换一下就可以了。

JavaScipt中如何实现函数缓存?函数缓存有哪些场景?

1、函数缓存是什么&#xff1f; 函数缓存就是将函数运行的结果进行缓存。本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09; 常用于缓存数据计算结果和缓存对象。 缓存只是一个临时的数据存储&#xff0c;它保存数据&#xff0c;以便将…

平衡二叉搜索树(AVL)——【C++实现插入、删除等操作】

本章完整代码gitee地址&#xff1a;平衡二叉搜索树 文章目录 &#x1f333;0. 前言&#x1f332;1. AVL树概念&#x1f334;2. 实现AVL树&#x1f33f;2.1 结构定义&#x1f33f;2.2 插入&#x1f490;左单旋&#x1f490;右单旋&#x1f490;左右双旋&#x1f490;右左双旋 &a…

MySql系列-常用命令

基础知识-常用命令 命令不区分大小写 1、mysql连接 mysql -u username -p 实例: mysql -u root -p 2、元数据查询 //服务器版本信息 SELECT VERSION( ) //当前数据库名 (或者返回空) SELECT DATABASE( ) //当前用户名 SELECT USER( ) //服务器状态 SHOW STATUS //服务…

C++项目实战——基于多设计模式下的同步异步日志系统-①-项目介绍

文章目录 专栏导读项目介绍开发环境核心技术环境搭建日志系统介绍1.为什么需要日志系统2.日志系统技术实现2.1同步写日志2.2异步写日志 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&a…