个人的spring面试总结

Spring面试经常会被问的东西

注:整理于各个网上的资料,由于太多我就不一个个的写出来了,我只是搬运工,我只是搬运工,我只是搬运工

  1. 循环依赖
  2. 事务
  3. ioc
  4. aop
  5. 生命周期
  6. 传播特性
  7. 设计模式
  8. 源码

谈一下spring的理解

spring是一个轻量级的框架,在全部的开发流程中所有的框架生产几乎都依赖于他,spring起了一个ioc容器的作用,用来承载bean对象,帮我们进行整个对象创建到销毁整个生命周期的管理,使用spring的时候可以使用配置文件,也可以使用注解来实现,当我们程序开始启动之后,要把定义好的bean对象转换成beandefinition,然后完成整个beandefinition解析加载过程。当我们获取到这些完整的对象之后,要对整个beandefinition进行实例化操作,在进行实例化的时候,最简单的方式是通过反射的方式创建实例化对象。

Spring Bean的作用域

spring bean的作用域分为5种,分别是 singleton、prototype、request、session、global-session这五种。
在这里插入图片描述

singleton

这个模式是单例的,使用这个模式,IOC容器只创建一个实例,并且每次返回都是这一个实例,这种模式是默认的模式,也是我工作中使用最多的模式。

prototype

prototype是原型模式,是多例的,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。并且prototype是在使用时创建的,销毁也不受IOC容器管理,而是GC来管理的。
注意:在工作中我遇到一种情况是service明明是prototype,但是我注入到singleton中的Controller中,却只有一个实例,那是因为,Controller是单例的Controller在初始化时,注入的service,这时service被初始化。为什么只是一个bean实例,是因为Controller只创建了一次。
证明:创建多个Controller都注入service,修改service的值并打印,发现每个Controller中打印出来的值并不一样。

request

request是请求模式,是在同一次请求中,IOC容器会创建一个单例bean,这次请求中返回的bean是同一个bean。
我在工作中是用request实现的缓存,同一次请求的缓存。这样会节省很多重复操作。

session

session是会话模式,在同一个会话中,IOC容器会创建一个单例bean,并且每次都会返回同一个bean。
这里和session类似,我使用它是用在会话级的缓存,我用来存放登陆时的用户权限信息,和角色信息。

global-session

这个模式,是所有的session 共享同一个bean。

具体使用:我使用的是注解@scope注解。、

Spring的七大核心模块

在这里插入图片描述

说说你对spring IOC和AOP的理解

1.IOC

许多应用都是通过彼此间的相互合作来实现业务逻辑的,如类A要调用类B的方法,以前我们都是在类A中,通过自身new一个类B,然后在调用类B的方法,现在我们把new类B的事情交给spring来做,在我们调用的时候,容器会为我们实例化。

  1. IOC容器的初始化过程

    资源定位,即定义bean的xml-------》载入--------》IOC容器注册,注册beanDefinition

    IOC容器的初始化过程,一般不包含bean的依赖注入的实现,在spring IOC设计中,bean的注册和依赖注入是两个过程,依赖注入一般发生在应用第一次索取bean的时候,但是也可以在xm中配置,在容器初始化的时候,这个bean就完成了初始化。

  2. 三种注入方式,构造器、接口、set注入,我们常用的是set注入

  3. bean是如何创建— 工厂模式

  4. 数据是如何注入-------反射

6.AOP

面向切面编程,在我们的应用中,经常需要做一些事情,但是这些事情与核心业务无关,比如,要记录所有update方法的执行时间时间,操作人等等信息,记录到日志,通过spring的AOP技术,就可以在不修改update的代码的情况下完成该需求。

7.AOP的实现原理------代理

请说说Spring中Bean的生命周期中有哪些步骤?

简单来说,总体是三个步骤:
bean的创建–>bean的初始化–>bean的销毁
仔细的说是这样:

  1. 解析类得到BeanDefinition
  2. 如果有多个构造方法,则要推断构造方法
  3. 确定好构造方法后,进行实例化得到一个对象
  4. 对对象中的加了@Autowired注解的属性进行属性填充
  5. 回调Aware方法,比如BeanNameAware,BeanFactoryAware调
  6. BeanPostProcessor的初始化前的方法
  7. 调用初始化方法
  8. 调用BeanPostProcessor的初始化后的方法,在这里会进行AOP
  9. 如果当前创建的bean是单例的则会把bean放入单例池
  10. 使用bean
  11. Spring容器关闭时调用DisposableBean中destory()方法

在这里插入图片描述

Spring框架中的单例Bean是线程安全的吗?

spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。
如果Bean是有状态的那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域把"singleton"改为"protopyte’这样每次请求Bean就相当于是new Bean()这样就可以保证线程的安全了。

  • 有状态就是有数据存储功能
  • 无状态就是不会保存数据controller、service和dao层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。

Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,Spring的事务管理器使用
Threadlocal为不同线程维护了一套独立的connection副本,保证线程之间不会互相影响(Spring 是如何保证事务获取同一个Connection的)
不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

你是如何理解Spring中的后置处理器的?

你是如何理解ApplicationContext和BeanFactory的?

Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,
DefaultListableBeanFactory 是整个spring ioc的始祖。

在这里插入图片描述

BeanFactory和ApplicationContent有什么区别

ApplicationContext是BeanFactory的子接口
ApplicationContext提供了更完整的功能:
①继承MessageSource,因此支持国际化。
②统—的资源文件访问方式。
③提供在监听器中注册bean的事件。
④同时加载多个配置文件。|
⑤载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

  • BeanFactory才用的是演示加载来注入Bean的,只有在使用某个Bean的时候,猜对Bean进行加载实例化,这样就不能发现一些存在spring的配置问题
  • ApplicationContext是在容器启动的时候一次性创造了所有的Bean,这样容器启动的时候,我们可以发现spring里面配置的错误,这样有利于检查所依赖是否注入。
  • 相对于BeanFactory,ApplicationContext唯一不足的就是占用内存空间,当程序配置很多,那么程序启动就慢
  • BeanFactory通常以编程的方式被创建,Applicationcontext还能以声明的方式创建,如使用ContextLoader。
  • BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而Applicationcontext则是自动注册。

在这里插入图片描述

请对比BeanFactory和FactoryBean的区别?

BeanFactory是spring中比较原始的Factory。它无法支持spring的许多插件,如AOP功能,Web应用等,ApplicationContext接口由Beanfactory接口派生而来,并对其功能进行了扩展。

BeanFactory与FactoryBean的区别:

相同点:都是接口

区别:

Beanfactory是一个工厂类,用于管理Bean的一个工厂,在spring中,所有的bean都是由BeanFactory(IOC容器)来进行管理的。

FactoryBean不是一个简单的bean,而是一个能生产或者修饰对象生成的工厂bean。其在IOC容器的基础上给bean的实现加上了一个简单工厂模式和装饰者模式,

  1. BeanFactory

BeanFactory负责生产和管理bean的一个工厂。它定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现。

在这里插入图片描述

FactoryBean

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。

FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。

在该接口中还定义了以下3个方法:
在这里插入图片描述
T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中

boolean isSingleton(): 返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;

Class getObjectType(): 返回FactoryBean创建的Bean类型。

当配置文件中的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身, 而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

Spring事务的实现方式和原理以及隔离级别

在使用Spring框架时,可以有两种使用事务的方式,一种是编程式的,一种是申明式的,@Transactional注解就是申明式的。

首先,事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行了扩展,以及提供了一些能让程序员更加方便操作事务的方式。

比如我们可以通过在某个方法上增加@Transactional注解,就可以开启事务,这个方法中所有的sql都会在一个事务中执行,统一成功或失败。

在一个方法上加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理 逻辑中就会将事务进行提交,如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚。

当然,针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置,默认情况下会对RuntimeException和Error进行回滚。

spring事务隔离级别就是数据库的隔离级别:外加一个默认级别

  • read uncommitted(未提交读)
  • read committed(提交读、不可重复读)· repeatable read(可重复读)
  • serializable (可串行化)
    数据库的配置隔离级别是Read commited , iltispring配置的隔离级别是Repeatable Read,请问这时隔离级别是以哪一个为准?
    以Spring配置的为准,如果spring设置的隔离级别数据库不支持,效果取决于数据库

Spring的事务什么时候会失效

spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了!常见情况有如下几种
1、发生自调用,类里面使用this调用本类的方法(this通常省略),此时这个this对象不是代理类,而是UserService对象本身!
解决方法很简单,让那个this变成UserService的代理类即可!
2、方法不是public的
@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 pub1ic 方法上,可以开启Aspect 代理模式。
3、数据库不支持事务
4、没有被spring管理
5、异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

什么是Bean的自动装配

开启自动z装配,只需要在xml配置文件里面定义“@Autowire”属性

<bean id="cutomer" class="com.xxx.xxx.Customer" autowire"/>

autowire属性有五种装配方式

  • no-缺省情况下,自动配置是通过“ref"属性手动设定。

手动装配:以va1ue或ref的方式明确指定属性值都是手动装配。
需要通过‘ref’属性来连接bean.

  • byName-根据bean的属性名称进行自动装配。
    cutomer的属性名称是person,spring会将bean id为sperson的bean通过setter方法进行自动装配。
<bean id="cutomer", c1ass="com.xxx.xxx.Cutomer" autowire="byName" />
<bean id=""person" class="com. xxx.XXx.Person" />
  • byType-根据bean的类型进行自动装配。
    cutomer的属性person的类型为Person,Spirng会将Person类型通过setter方法进行自动装配。
<bean id="cutomer" class="com. xxx .xxx. Cutomer" autowire="byType" />
<bean id="person" class="com. xxx . xxx.Person" />
  • constructor-类似byType,不过是应用于构造器的参数。如果一个bean与构造器参数的类型形同,则进行自动装配,否则导致异常。

cutomer构造函数的参数person的类型为Person,Spirng会将Person类型通过构造方法进行自动装配。

<bean id="cutomer" class="com.xxx.xxx.Cutomer" autowire="construtor" />
<bean id="person" class="com. xxx.xxx.Person" />
  • autodetect-如果有默认的构造器,则通过constructor方式进行自动装配,否则使用byType方式进行自动装

如果有默认的构造器,则通过constructor方式进行自动装配,否则使用byType方式进行自动装配。
@Autowired自动装配bean,可以在字段、 setter方法、构造函数上使用。

Spring中到底有几种依赖注入的方式?

  1. set注入
  2. 构造方法注入
  3. 接口注入

@Configuration注解的作用和底层原理是什么?

加上@Configuration注解主要是给我们的类加上了cglib代理。在执行我们的配置类的方法时,会执行cglib代理类中的方法,其中有一个非常重要的判断,当我们的执行方法和我们的调用方法是同一个方法时,会执行父类的方法new(cglib代理基于继承);当执行方法和调用方法不是同一个方法时会调用beanFactory.getBean获取。

@Transactional注解的作用?

此注解是Spring注解配置事务的核心注解,无论是注解驱动开发还是注解和XML混合开发,只有涉及配置事务采用注解的方式,都需要使用此注解。
通过源码我们看到,该注解可以出现在接口上,类上和方法上。分别表明;

  • 接口上:当前接口的所有实现类中重写接口的方法有事务支持。
  • 类上:当前类中所有方法有事务支持。
  • 方法上:当前方法有事务的支持。

优先级:方法上>类上>接口上。

Spring中是如何解决循环依赖的?

  • 问:Spring中循环依赖了解吗?
  • 答:是一个BeanA中依赖BeanB,然后BeanB中也依赖BeanA,当然也可以是更多Bean之间的循环依赖,A依赖B,B依赖C,C依赖A这种
  • 问:嗯,那你知道循环依赖有哪几种形式吗?
  • 答:嗯,因为我们依赖注入的时候,可以是属性注入,也可以是构造方法注入,也可以是setter方法注入,因此对应有三种循环依赖的形式。
  • 问:嗯,那你知道这几种循环依赖,哪些是没有问题的,哪些是程序会报错导致不能启动的吗?
  • 答:… 好像构造依赖会报错,其他两种是不会报错的,程序是可以正常启动的。
  • 问:嗯,那你知道为什么吗?为何构造循环依赖会报错?其他的循环依赖却可以正确的运行呢?
  • 答:这个…好像不太清楚啊,可以要看看Bean的生命周期才知道哦…

代理模式

  1. 静态代理
  2. 动态代理
    在这里插入图片描述

静态代理:

角色分析:

  • 抽象角色:一般使用接口或者抽象类
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些操作
  • 客户:访问代理对象的人

代码步骤:

  • 接口
  • 真实角色
  • 代理角色
  • 客户访问代理角色

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不需要关注公共业务
  • 公共业务交给代理角色,实现分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率变低

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的类是动态生成的不是我们自己写好的
  • 动态代理分为两大类:
    基于接口:JDK动态代理
    基于类:cglib
    java字节码:javassist
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code_BinBin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值