Spring面试题

目录

1、说说Spring里用了哪些设计模式?

2:BeanFactory和FactoryBean区别

3:BeanFactory和ApplicationContext区别 

4:说说SpreingBean的生命周期

5.Spring如何解决循环依赖

6:为什么要三级缓存,二级缓存不可以吗?

七:什么是SpringAop

八:Spring的通知类型有哪些 

九:什么是织入(weaving)?

十:什么是SpringIOC容器,其作用是什么

十一:什么是依赖注入

十二:依赖注入的三种方法

十三:Spring框架中的单例bean是线程安全的吗

十四:Spring如何处理线程并发问题?


1、说说Spring里用了哪些设计模式?

单例模式:Spring 中的 Bean 默认情况下都是单例的。

工厂模式:工厂模式主要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象。

代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理。

观察者模式:spring的事件驱动模型使用的是 观察者模式 ,Spring中Observer模式常用的地方是listener的实现。

事件机制的实现需要三个部分,事件源,事件,事件监听器 

事件(ApplicationEvent):负责对应相应监听器事件源发生某事件是特定事件监听器被触发的原因。

监听器(ApplicationListener):对应于观察者模式中的观察者。监听器监听特定事件,并在内部定义了事件发生后的响应逻辑。

事件发布器(ApplicationEventMulticaster): 对应于观察者模式中的被观察者/主题,负责通知观察者对外提供发布事件和增删事件监听器的接口,维护事件和事件监听器之间的映射关系,并在事件发生时负责通知相关监听器

模板方法模式:主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。

2:BeanFactory和FactoryBean区别

BeanFactory是bean的工厂,BeanFactory只是个接口,使用了简单工厂模式,负责生产bean

FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它最终是调用getObject这个方法来返回最终的bean。它的实现与设计模式中的工厂模式和修饰器模式类似。

3:BeanFactory和ApplicationContext区别 

BeanFactory和ApplicationContext都有制造桌子的能力,但是他们的区别在于BeanFatory他需要自己从头到尾制造图纸,一步一步自己做,ApplicationContext不一样,它可以有很多人帮他一起做这个椅子;(就直接说法,BeanFactory少了refesh里面的十二个方法)

  • Bean 工厂(com.springframework.beans.factory.BeanFactory)是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
  • 应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory 基础之上。

4:说说SpreingBean的生命周期

  1. 实例化,创建一个Bean对象

  2. 填充属性,为属性赋值

  3. 初始化

    • 如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源

    • 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzationpostProcessAfterInitialization方法

    • 如果配置了init-method方法,则会执行init-method配置的方法

  4. 销毁

    • 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法

    • 如果配置了destroy-method方法,则会执行destroy-method配置的方法

5.Spring如何解决循环依赖

何为循环依赖:即2个或以上bean 互相持有对方,最终形成闭环。

本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。

第一级缓存:用来保存实例化、初始化都完成的对象

第二级缓存:用来保存实例化完成,但是未初始化完成的对象

第三级缓存:用来保存一个对象工厂,提供 一个匿名内部类,用于创建二级缓存中的对象

A对象的创建过程:

  1. 创建对象A,注入属性时,发现依赖B,转而去实例化B

  2. 同样创建对象B,注入属性时发现依赖A,从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入一级缓存。

  1. 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存

  2. 最后,一级缓存中保存着实例化、初始化都完成的A、B对象

因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。

6:为什么要三级缓存,二级缓存不可以吗?

二级缓存的作用是和成熟的Bean做分离

三级缓存的目的就是为了解耦,三级缓存存的是函数接口,调用的是我们的bean后置处理器

不可以,主要是为了生成代理对象。

使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

只要两个缓存确实可以做到解决循环依赖的问题,但是有一个前提这个bean没被AOP进行切面代理,如果这个bean被AOP进行了切面代理,那么只使用两个缓存是无法解决问题
果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象

七:什么是SpringAop

Aop即是面向切面编程,它与OOP面向对象编程相辅相成

  • Aspect(切面):Aspect 声明类似于 Java 中的类声明
  • Joint point(连接点):连接点是在应用执行过程中能够插入切面(Aspect)的一个点。这些点可以是调用方法时、甚至修改一个字段时。
  • Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方
  • Advice(增强):Advice定义了在Pointcut里面定义的程序具体要做的操作,它通过before,after,around来区别是在每个joint point之前,之后还是替代代码执行。
  • Target(目标对象):织入 Advice 的目标对象.。
  • Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

八:Spring的通知类型有哪些 

pring切面可以应用5种类型的通知:
1. 前置通知(Before):在目标方法被调用之前调用通知功能;
2. 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法 的输出是什么;
3. 返回通知(After-returning ):在目标方法成功执行之后调用通知;
4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
5. 环绕通知(Around):把前置通知和后置通知都写到一个通知中,组成了环绕通知
PS:
前置通知中,会先把前置方法压入栈底,然后执行完前置方法,释放,再到目标方法。。以此类推
环绕通知中,前置方法执行完后不会被释放,而是要等目标方法与后置方法,最后释放后置方法。。。以此类推

九:什么是织入(weaving)?

Spring AOP 框架仅支持有限的几个 AspectJ 切入点的类型,它允许将切面运用到在 IoC 容器中声明的 bean 上。如果你想使用额外的切入点类型或者将切面应用到在 Spring IoC 容器外部创建的类,那么你必须在你的 Spring 程序中使用 AspectJ 框架,并且使用它的织入特性。

十:什么是SpringIOC容器,其作用是什么

SpringIOC即是把对象的控制权交给Spring容器,Spring容器负责创建对象,管理对象(依赖注入DI)装配对象,配置对象,并且负责管理对象的生命周期

作用:

(1)减低代码的耦合度,让容器去维护具体的对象

(2)管理对象的创建和依赖关系的维护

十一:什么是依赖注入

通过DI(Dependency Injection,依赖注入)来实现---> 动态的向某个对象提供它所需要的其他对象。

依赖注入过程中,如果类A中有类B,然后类B的访问权限是private,那么我们在XML里面就需要通过内部类的方式来获取类B,而不能单纯通过set方法获得

<bean name="A" class="domain.A">
    <property name="name" value="001">
    <property name="B">
        <bean name="B" class="domain.B>
            <constructor-arg name="name" value="555"></constructor>
        </bean> 
    </property>
</bean>

十二:依赖注入的三种方法

(1)构造方法注入---->有参构造函数

<bean>

        <constructor-arg name="属性名" value="属性值" type="">

</bean>

(2)Set方法---->无参构造函数+set方法

<bean>

        <property name="属性名" value="属性值">

</bean>

(3)注解@Autowired

<bean name="xxx" class="xxx" autowire="xxx"> </bean>
  • no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。

  • byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。

  • byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。

  • 构造函数 - 它通过调用类的构造函数来注入依赖项。它有大量的参数。

  • autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配

十三:Spring框架中的单例bean是线程安全的吗

不是,Spring框架中的单例bean不是线程安全的。

spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线 程的封装处理。

实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来 说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那 就要开发者自己去保证线程安全了,

最简单的就是改变 bean 的作用域, 把“ singleton”变更为“prototype”,这样请求 bean 相当于 new Bean() 了,所以就可以保证线程安全了。

有状态就是有数据存储功能。 无状态就是不会保存数据

十四:Spring如何处理线程并发问题?

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中, 绝大部分Bean都可
以声明为singleton作用域,因为Spring对一些Bean中非线 程安全状态采用ThreadLocal进行处理,
解决线程安全问题
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对 数据的访问冲突。
因为每一个线程都拥有自己的变量副本,从而也就没有必要对 该变量进行同步了。ThreadLocal提
供了线程安全的共享对象,在编写多线程代 码时,可以把不安全的变量封装进ThreadLocal
-------------------------

十五:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值