Spring面试题

1. Spring 用到了哪些设计模式

简单工厂模式:BeanFactory就是简单工厂模式的体现

工厂方法模式:FactoryBean就是典型的工厂方法模式。spring在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法。每个 Bean 都会对应一个 FactoryBean,如 SqlSessionFactory 对应 SqlSessionFactoryBean。

单例模式:一个类仅有一个实例,提供一个访问它的全局访问点。Spring 创建 Bean 实例默认是单例的。

适配器模式:SpringMVC中的适配器HandlerAdatper。由于应用会有多个Controller实现,如果需要直接调用Controller方法,那么需要先判断是由哪一个Controller处理请求,然后调用相应的方法。当增加新的 Controller,需要修改原来的逻辑,违反了开闭原则(对修改关闭,对扩展开放)。 为此,Spring提供了一个适配器接口,每一种 Controller 对应一种 HandlerAdapter 实现类,当请求过来,SpringMVC会调用getHandler()获取相应的Controller,然后获取该Controller对应的 HandlerAdapter,最后调用HandlerAdapter的handle()方法处理请求,实际上调用的是Controller的handleRequest()。每次添加新的 Controller 时,只需要增加一个适配器类就可以,无需修改原有的逻辑。

常用的处理器适配器:SimpleControllerHandlerAdapter,HttpRequestHandlerAdapter,AnnotationMethodHandlerAdapter。

代理模式:spring 的 aop 使用了动态代理,有两种方式JdkDynamicAopProxy和Cglib2AopProxy。

观察者模式:spring 中 observer 模式常用的地方是 listener 的实现,如ApplicationListener。

模板模式: Spring 中 jdbcTemplate、hibernateTemplate 等,就使用到了模板模式

2. IOC容器初始化过程

从XML中读取配置文件。将bean标签解析成 BeanDefinition,如解析 property 元素, 并注入到 BeanDefinition 实例中。将 BeanDefinition 注册到容器 BeanDefinitionMap 中。BeanFactory 根据 BeanDefinition 的定义信息创建实例化和初始化 bean。单例bean的初始化以及依赖注入一般都在容器初始化阶段进行,只有懒加载(lazy-init为true)的单例bean是在应用第一次调用getBean()时进行初始化和依赖注入。// AbstractApplicationContext // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); 多例bean 在容器启动时不实例化,即使设置 lazy-init 为 false 也没用,只有调用了getBean()才进行实例化。loadBeanDefinitions采用了模板模式,具体加载 BeanDefinition 的逻辑由各个子类完成。#

3. Bean的生命周期

1.调用bean的构造方法创建Bean 2.通过反射调用setter方法进行属性的依赖注入 3.如果Bean实现了BeanNameAware接口,Spring将调用setBeanName(),设置 Bean的name(xml文件中bean标签的id) 4.如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()把bean factory设置给Bean 5.如果存在BeanPostProcessor,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法,在Bean初始化前对其进行处理 6.如果Bean实现了InitializingBean接口,Spring将调用它的afterPropertiesSet方法,然后调用xml定义的 init-method 方法,两个方法作用类似,都是在初始化 bean 的时候执行 7.如果存在BeanPostProcessor,Spring将调用它们的postProcessAfterInitialization(后初始化)方法,在Bean初始化后对其进行处理 8.Bean初始化完成,供应用使用,这里分两种情况: 8.1 如果Bean为单例的话,那么容器会返回Bean给用户,并存入缓存池。如果Bean实现了DisposableBean接口,Spring将调用它的destory方法,然后调用在xml中定义的 destory-method方法,这两个方法作用类似,都是在Bean实例销毁前执行。 8.2 如果Bean是多例的话,容器将Bean返回给用户,剩下的生命周期由用户控制。

4. BeanFactory和FactoryBean的区别?

BeanFactory:管理Bean的容器,Spring中生成的Bean都是由这个接口的实现来管理的。

FactoryBean:通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,直接用xml配置比较麻烦,这时可以考虑用FactoryBean,可以隐藏实例化复杂Bean的细节。当配置文件中bean标签的class属性配置的实现类是FactoryBean时,通过 getBean()方法返回的不是FactoryBean本身,而是调用FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。如果想得到FactoryBean必须使用 '&' + beanName 的方式获取。

Mybatis 提供了 SqlSessionFactoryBean,可以简化 SqlSessionFactory的配置:

5. Bean注入容器有哪些方式?

1、@Configuration + @Bean

@ComponentScan放置在我们的配置类上,然后可以指定一个路径,进行扫描带有特定注解的bean,然后加至容器中。特定注解包括@Controller、@Service、@Repository、@Component

@Import注解导入

实现BeanDefinitionRegistryPostProcessor进行后置处理。

使用FactoryBean接口

6. Spring自动装配的方式有哪些?

byType(根据类型),byName(根据名称)、constructor(根据构造函数)。

Spring怎么解决循环依赖的问题?

首先,有两种Bean注入的方式。构造器注入和属性注入。对于构造器注入的循环依赖,Spring处理不了,会直接抛出BeanCurrentlylnCreationException异常。 对于属性注入的循环依赖(单例模式下),是通过三级缓存处理来循环依赖的。而非单例对象的循环依赖,则无法处理。 下面分析单例模式下属性注入的循环依赖是怎么处理的: 首先,Spring单例对象的初始化大略分为三步: createBeanInstance:实例化bean,使用构造方法创建对象,为对象分配内存。 populateBean:进行依赖注入。 initializeBean:初始化bean。 Spring为了解决单例的循环依赖问题, 使用了三级缓存: singletonObjects:完成了初始化的单例对象map,bean name --> bean instanceearlySingletonObjects :完成实例化未初始化的单例对象map,bean name --> bean instancesingletonFactories : 单例对象工厂map,bean name --> ObjectFactory, 单例对象实例化完成之后会加入singletonFactories。在调用createBeanInstance进行实例化之后, 会调用addSingletonFactory,将单例对象放到singletonFactories中。

假如A依赖了B的实例对象,同时B也依赖A的实例对象。A首先完成了实例化,并且将自己添加到singletonFactories中接着进行依赖注入, 发现自己依赖对象B,此时就尝试去get(B)发现B还没有被实例化,对B进行实例化然后B在初始化的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects和二级缓存earlySingletonObjects没找到,尝试三级缓存singletonFactories,由于A初始化时将自己添加到了singletonFactories,所以B可以拿到A对象,然后将A从三级缓存中移到二级缓存中B拿到A对象后顺利完成了初始化,然后将自己放入到一级缓存singletonObjects中此时返回A中,A此时能拿到B的对象顺利完成自己的初始化由此看出,属性注入的循环依赖主要是通过将实例化完成的bean添加到singletonFactories来实现的。而使用构造器依赖注入的bean在实例化的时候会进行依赖注入,不会被添加到singletonFactories中。比如A和B都是通过构造器依赖注入,A在调用构造器进行实例化的时候,发现自己依赖B,B没有被实例化,就会对B进行实例化,此时A未实例化完成,不会被添加到singtonFactories。而B依赖于A,B会去三级缓存寻找A对象,发现不存在,于是又会实例化A,A实例化了两次,从而导致抛异常。

总结:1、利用缓存识别已经遍历过的节点; 2、利用Java引用,先提前设置对象地址,后完善对象。

相关推荐
砍材农夫1 小时前
物联网实战|Spring Boot MQTT平台 |emqx broker实战
spring boot·spring·spring cloud·mybatis
2401_894915534 小时前
GEO 定位优化源码搭建常见报错排查:数据库、伪静态、接口调试
java·数据库·网络协议·tcp/ip·spring·unity
wangjialelele6 小时前
Spring Cloud 全体系学习笔记(REST、Nacos、Feign、Gateway)
java·spring boot·笔记·学习·spring·spring cloud·gateway
玖石书6 小时前
ASP.NET Core迁移Spring对照系列:文件系统操作篇
spring·asp.net
xqqxqxxq6 小时前
吃透 Spring 高频注解(包含SpringMVC Spring Boot)
java·spring boot·spring
攻城有术18 小时前
专项攻克——spring、springMVC、springBoot、springCloud的启动流程
spring boot·spring·spring cloud
markinmarkin21 小时前
Spring 中有哪些方式可以把Bean 注入到IOC 容器?
java·spring
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ1 天前
Spring‑AI Document 对象 JSON 字段详解
人工智能·spring·json
麻雀聊技术1 天前
一重启 AI 就失忆?用 Spring AI + PostgreSQL 3步搞定“长期记忆”持久化(附完整代码)
java·spring·openai
he___H1 天前
Spring-Configur注解
java·spring