Spring面试

(1条消息) Spring常见面试题总结(超详细回答)_张维鹏的博客-优快云博客_spring面试题

  1. IOC控制反转:

    控制是指将所有的类都托管给Spring创建和管理

    反转是指通过依赖注入的方式,给对象的属性赋值,包括基本属性和引用属性

  2. AOP面向切面编程:

    本质是动态代理模式(类似于装饰者模式)

    通过横切的方式在原有的业务代码之上添加公共功能,而不改变原有业务代码

扩展:代理模式和装饰者模式

代理模式:

代理模式包含代理对象,被代理对象

image-20210916142318813

静态代理:

  1. 代理对象Proxy和被代理对象RealSubject都继承了Subject接口。客户端调用Proxy的方法,而Proxy则把具体操作委托给RealSubject执行。

  2. 在Client中,首先创建了一个realSubject对象,然后创建了一个代理对象proxy并把realSubject对象通过构造器传入进去。最后调用proxy的方法,实际还是调用realSubject的方法。

  3. 代理对象和被代理对象需要实现相同的接口

动态代理:

  1. 通过动态代理,创建一个实现了InvocationHandler接口的DynamicProxy类,通过这个类可以在运行期为各种对象创建对应的代理。

  2. DynamicProxy类实现了InvocationHandler接口,这个接口中有一个invoke方法,被代理的对象的任何方法都是在invoke中调用。

  3. 在Client中,先创建一个realSubject,然后把它传入DynamicProxy的构造函数中。但是在这个DynamicProxy还不是我们需要的代理,毕竟它没有实现Subject接口。

    在通过Proxy.newProxyInstance创建一个Subject对象,也就是最终的代理对象。

装饰者模式:

  1. 装饰者对被装饰者进行了功能的扩展,但是又不修改被装饰者的相应代码;

    只为每个功能编写一个装饰类,在运行时组合不同的对象即可实现所需的功能组合。

  2. 代理模式和在装饰者模式都有很多的应用,具有一定的相似性,都是通过一个新的对象封装原有的对象。

    二者的差异在于代理模式是为了实现对象的控制,可能被代理的对象难以直接获得或者是不想暴露给客户端;

    装饰者模式是继承的一种替代方案,在避免创建过多子类的情况下为被装饰者提供更多的功能。

1.Spring是什么?

Spring是一个轻量级的IOC和AOP容器框架,目的是为了简化企业级应用程序的开发,使得开发者只需要关注业务需求。主要包括以下七个模块:

  • Spring Core:核心类库,提供IOC和DI服务

  • Spring AOP

  • Spring WebMVC 提供面向web应用的MVC实现

  • Spring ORM 对象关系映射

  • Spring DAO 对JDBC抽象封装、

  • Spring Context 提供框架式的Bean访问方式,以及企业级功能

  • Spring Web 提供基本的面向Web的综合特性

2.Spring的优点?

  • 属于低侵入式设计(业务的类不需要集成框架的类)
  • IOC实现了对象由Spring创建和管理,对象之间的依赖关系交给Spring处理;对象之间的引用不采用在程序中硬编码,降低了组件的耦合性
  • 提供了AOP技术,支持将一些通用任务(如日志、事务)进行集中式管理,从而提供更好的复用
  • spring对于在主流的应用框架提供了集成支持(如mybatis等)

3.对IOC的理解?

  • IOC控制反转,控制指的是对象由Spring容器进行创建和管理,反转指的是对象之间的依赖关系也交给Spring处理,降低了对象之间的耦合性。

    DI依赖注入和控制反转是同一个概念不同角度的描述,是指在运行时 通过IOC容器 动态注入对象所需要的外部依赖,给对象的属性赋值。

  • 最直观的表达就是:以前创建和引用对象都是在程序中硬编码的;IOC让创建对象不用再去new了,对象由Spring创建和管理;

  • IOC的依赖注入方式:构造器注入(只能有参构造),set方法注入(需要有无参构造);c空间和p空间中注入;注解注入

4.AOP理解

OOP面向对象,适合纵向开发,但是不适合横向开发,会导致大量代码的重复,而不利于各个模块的复用。

AOP面向切面,将那些与业务无关的公共行为(日志、事务)抽取封装成一个可复用的模块,这个模块被命名为Aspect。减少系统中的重复代码,降低模块间的耦合度。

AOP的实现关键在于代理模式,代理模式分为静态代理和动态代理;

  • 代理模式中有代理对象和被代理对象,都实现了一个抽象接口,在Client中创建被代理对象,将其传入到代理对象构造方法中。

  • 静态代理称为编译时增强,在编译时生成代理类,并将切面织入到Java字节码中,运行时就是增强之后的AOP对象

  • SpringAOP使用的是动态代理。通过动态代理,创建一个实现了InvocationHandler接口的DynamicProxy类,通过这个类可以在运行期为各种对象创建对应的代理。

    ==DynamicProxy类实现了InvocationHandler接口,这个接口中有一个invoke方法,被代理的对象的任何方法都是在invoke中调用。==动态地将横切逻辑和业务编织在一起;

  • 静态代理和动态代理区别在于生成代理对象的时机不同

IOC让相互协作的组件保持松散的耦合,AOP允许将公共通用功能剥离出来封装称为一个单独的可复用的模块。

5.AOP里面的几个名词的概念

  • 切面(Aspect):被抽取出来的公共模块,切入类,可能会用来横切多个对象;Aspect切面由多个Pointcut切点和Advice通知组成;

  • 切点(Pointcut):公共类中的方法

  • 通知(Advice):指在连接点上执行的动作,增加的逻辑,Before(在连接点之前执行的通知)、After、Around;AfterReturning(连接点正常完成后通知)、AfterThrowing(连接点异常退出时执行的通知)

  • 目标对象(Target):包含连接点的对象,被通知的对象;SpringAOP是通过动态代理实现的,所以这个对象永远是一个代理对象。

  • 连接点(Joinpoint):目标对象中一个方法(在这个方法前后执行增强)

  • 织入:通过动态代理,在目标对象的方法(即joinpoint)中执行增强逻辑(Advice)的过程。

image-20210916160433765

【6.Spring容器的启动流程】

(1)初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中

(2)将配置类的BeanDefinition注册到容器中

(3)调用refresh()方法刷新容器

7.BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。

(1)BeanFactory是Spring里面最底层的接口,是IOC的核心,定义了IOC的基本功能,包括了各种Bean的定义、加载、实例化、依赖注入和生命周期管理。

​ ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能。

(2)BeanFactory采用延迟加载的形式注入Bean,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。

​ ApplicationContext是在容器启动时,一次性创建了所有的Bean。可以在容器启动时,发现Spring中存在的配置错误,这样有利于检查所依赖属性的是否注入。

(3)BeanFactory和ApplicationContext都支持BeanPostProcessor和BeanFactoryPostProcessor的使用;但是BeanFactory需要手动注册,ApplicationContext自动注册。

(4)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

【9.SpringBean的生命周期?】

简单来说,SpringBean的生命周期只有四个阶段:实例化Instantiation== >属性赋值Populate== >初始化Initialization == >销毁Destruction

【10.Spring中bean的作用域】

(1)singleton:默认作用域,单例bean,每个容器中只有一个bean实例

(2)prototype:为每个bean请求创建一个实例

(3)request:为每个request请求创建一个实例,在请求完成后,bean会失效并被GC回收

(4)session:为每个session会话创建一个实例

(5)global-session:所有会话共享一个实例

11.Spring框架中Bean是线程安全的吗?如果线程不安全,那么如何处理?

Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况需要结合Bean的作用域来看:

(1)对于prototype作用域的Bean,每次都创建一个新对象,因此线程之间不存在Bean的共享,所以不存在线程安全问题

(2)对于Singleton作用域的Bean,所有的线程共享一个单例实例的Bean,因此存在线程安全问题。但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类、Dao等,这些Bean大多是无状态的,只关注方法本身。

  • 有状态的Bean:就是有实例变量的对象,可以保存数据,是非线程安全的。

  • 无状态的Bean:就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。

对于有状态的Bean,需要自行保证线程安全,最简单的解决办法就是将Bean的作用域由singleton改为prototype。

  • 采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的变量副本
  • 线程同步,加锁阻塞

12.Spring注入bean的几种方式

  • 构造器注入(有参构造注入)
  • set方法注入(需要有无参构造方法)
  • c空间注入,p空间注入

【13.Spring如何解决循环依赖问题?】

循环依赖问题在Spring中主要有三种情况:

(1)通过构造方法进行依赖注入时,产生的循环依赖问题

(2)通过setter方法进行依赖注入时,且在原型模式下,产生的循环依赖问题

(3)通过setter方法进行依赖注入时,且在单例模式下,产生的循环依赖问题

在Spring中,只有第(3)中方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。

  • 第一种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
  • 第二种setter方法(多例)的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。

Spring在单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要功臣。解决的核心原理就是:在对象实例化之后,依赖注入之前,Spring提前暴露的Bean实例的引用在第三级缓存中进行存储。

14.Spring的自动装配

在Spring中,使用autowire来配置自动装配。对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋给各个对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值