面试--spring基础

1、为什么使用spring
  • 轻量级框架,基本版本大约2M

  • 实现IOC和DI,通过IOC容器实现Bean的生命周期的管理,通过DI实现依赖注入,实现对象依赖的松耦合

  • 实现AOP,面相切面

  • 基于spring的springmvc和springboot等轻量级框架

  • 通过AOP实现事务的统一管理

2、spring的事务传播行为
  • required:默认,如果存在事务则加入,不存在则新建

  • require_new:不管是否存新建

  • nested:如果存在当前事务则嵌套,不存在则新建

  • supports:支持当前事务,不存在则以非事务方式执行

  • not_supported:非事务执行,如果存在当前事务则挂起

  • mandatory:强制事务执行,不存在抛异常

  • never:强制非事务执行,存在抛异常

3、spring bean生命周期的执行流程
  • 创建前:通过注解或者配置类等加载bean,程序启动后,将bean对象转换成一个BeanDefination对象,对它进行解析和加载

  • 创建实例:反射创建Bean实例,并且扫描和解析Bean声明的一些属性

  • 依赖注入:根据BeanDedinition的信息进行依赖注入,populateBean完成属性的注入。

  • 容器缓存:调用Aware接口的相关方法,完成对beanName、beanClassLoader、beanFactory对象的属性设置;调用前置处理方法、initMethod、后置处理方法。

  • 销毁:spring应用上下文关闭时,所有的bean都会被销毁。如果存在实现了DisposableBean接口或配置了destory-method属性,会被调用

4、bean的作用域spring的单例和多例模式
  • 单例:spring容器只会创建一个Bean的实例,在整个程序中共享。每次获取该bean时,都会返回同一个实例对象。默认情况下,是单例的。

  • 多例:scope="prototype",每次请求获取Bean都会创建一个新的实例,每个实例都是独立的。

基于spring框架的web应用里,增加了一个会话维度控制bean生命周期

  • request:每次请求创建一个新的bean

  • session:同一个session共享一个bean

  • globalSession:全局session共享一个bean

5、bean是线程安全的吗

多例bean每次都会创建新实例,因此不存在线程安全问题

单例bean是共享一个实例,可能存在线程安全问题。单例bean又分为有状态bean和无状态bean。

多线程中只对bean的成员变量查询不改变的称为无状态bean,不存在线程安全问题

多线程中对bean成员变量更新操作称为有状态bean,存在线程安全问题

解决:

  • 将作用域右单例改为多例

  • 定义threadLocal成员变量,将需要的可变成员变量保存到其中,相当于为每个线程提供了一个独立的变量副本,每个线程只需要操作自己的副本

6、spring中如何把bean注入到IOC中
  • XML声明的bean定义

  • @Import,导入配置类或普通的bean

  • @Configuration,声明配置类,使用@Bean实现bean的定义

  • @CompontScan,声名@Controller、@Service等的注解的类

  • 使用FactoryBean,动态构建一个 Bean 实例,OpenFeign动态代理实例就是使用FactoryBean 实现的

  • 实现ImportBeanDefinitionRegistrar接口,动态注入 Bean 实例。在SpringBoot启动注解有用到。

  • 实现ImportSelector接口,动态批量注入配置类或者 Bean 对象,在 SpringBoot 自动装配机制里用到。

7、spring IOC的理解

控制反转,就是把对对象的管理交给容器,需要使用对象实例,直接从IOC容器中获取,降低对象与对象之间耦合性。

有很多方式去定义bean,XML文件、@Service、@Configution,@Componet等,在spring启动的时候,回去解析bean然后保存到IOC容器中。

  • IOC初始化,通过各种方式解析和加载后生成BeanDefinition实体,实体包含bean基本属性,然后注册到IOC

  • bean初始化及依赖注入,通过反射对没有设置lazy-init的单例bean进行初始化,完成依赖注入

  • 通过@AutoWired或则getBean从容器获取bean并使用,对设置lazy-init的单例bean的实例化是在每次获取bean的时候,调用bean的初始化方法完成实例化的,容器不会去管理这些bean

8、对DI的理解

依赖注入,如果Bean之间存在依赖关系,那么IOC需要自动实现依赖对象的实例注入

接口注入、setter注入、构造器注入、@Autowired等注解

9、spring中BeanFactory 和 FactoryBean 的区别
  • BeanFactory是所有spring bean的顶级接口,为spring容器定义一套规范,并提供getBean这样的方法从容器中获取指定的Bean实例。在产生bean的同时,提供了解决bean之间依赖注入的能力。

  • FactoryBean是一个工厂bean,是一个接口,主要是动态生成一个类型的bean实例,有一个getObject方法就是用来实现动态构建Bean的过程

10、对AOP的理解

创建代理对象:调用getBean(),创建实例后,根据AOP的配置去匹配目标类的类名,是否满足切面规则,然后调用ProxyFactory创建代理bean并缓存到IOC容器,选择代理策略,如果目标类实现了接口默认选择JDK代理,否则使用bglib代理。

拦截目标对象:AopProxy拦截,调用invocationHandler的invoke(),触发MethodInvocation的proceed(),按顺序执行符合所有AOP拦截规则的拦截器链

调用代理对象:反射调用Advice对象,执行织入代码

调用目标对象:执行MethodInterceptor 的 invoke(), 调用目标对象

JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

cglib代理:CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并在拦截方法相应地方织入横切逻辑。

11、@Resource 和@Autowired的区别
  • @Resource :JDK提供的注解,可以根据name和type匹配,默认是name

  • @Autowired :required 属性默认值是 true,表示强制要求 bean 实例的注入;

    根据type匹配,如果需要支持name就要配合@Primary或者@Qualifier实现

12、@Conditional

判断bean是否满足条件,再装载IOC中

可以实现Condition接口并重写matches方法

13、spring中,两个相同的id的bean会报错吗
  • 如果在同一个xml中相同id的bean,启动时会报错,因为id标识bean的唯一标识符,是在对xml文件解析转化为beanDefinition的阶段

  • 不同的xml文件里,可以存在id相同的,IOC加载bean的时候会覆盖

  • 如果使用@Configuration,声明多个名称相同的bean,只会注册第一个实例

  • 如果使用@Autowired,根据类型,启动报错找不到

  • 如果使用@Resource,根据名称,报错类型不匹配

14、spring如何解决循环依赖的

循环依赖是两个或者多个bean相互持有对方的引用造成的死循环问题

spring设计了三级缓存解决。当调用getBean方法的时候,spring先从一级缓存找bean,如果一级缓存没有就去二级缓存找,如果都没有,意味着bean没有实例化,然后spring容器会实例化bean,将bean放入二级缓存,同时加上标记是否存在循环依赖,如果存在就将bean放入二级缓存,等待下一次轮询赋值,也就是解析@Autowired注解,等赋值完成后,将bean存入一级缓存。

三级缓存什么作用?

三级缓存是用来存储代理bean,当调用getBean时,发现目标bean需要通过代理工厂创建,就会将创建好的实例保存到三级缓存,最终赋值完成的bean同步到一级缓存

spring哪些情况下,不能解决循环依赖?

  • 多例bean通过setter注入,需要改成单例

  • 构造器注入的bean,可以使用@Lazy

  • 单例的代理bean通过setter注入,可以使用@Lazy

  • @DependsOn注解的,找到循环的地方,迫使不循环

15、spring的事务和分布式事务的使用如何区分,以及联系

spring没有提供事务,只是提供了对数据库事务管理的封装,通过声明式的事务配置,本质上就是数据库蒙面的事务

分布式事务,是解决多个数据库的事务操作的数据一致性问题

使用上没有关联,可以使用Seata

16、对springmvc的理解

采用了MVC架构,model、view、controller分离

  • 文件处理器:用于处理上传请求

  • 当前环境处理器:视图解析、用到国际化资源或主题的时候

  • 主题处理器:解析主题,解析仰视、图片和形成的显示效果的集合

  • 处理器映射器:每个请求都需要一个Handler处理,HandlerMapping就是找到请求相应的处理器

  • 处理器适配器:让固定的servlet处理方法调用灵活的Handler进行处理

  • 异常处理器:处理其他组件产生的异常情况

  • 视图名称翻译器:从请求中获取ViewName,有的Handler处理完后没有设置view也没viewName,就要从请求获取

  • 页面渲染处理器:将string类型的视图名和Locale解析为view类型的视图

  • 参数传递管理器:处理完post请求后重定向到另一个get请求,这个get请求可以返回页面渲染需要的信息

HandlerMapping 回到调用 HandlerAdapter

HandlerAdapter 会返回 ModelAndView

ModelAndView 根据用户传入参数得到 ViewResolvers

ViewResolvers 会将用户传入的参数封装为 View,交给引擎进行渲染。

17、spring mvc执行流程
  • 发起请求,被servlet拦截转发给mvc框架

  • DispatchSerlvet核心控制器,接收到请求并转发给HandlerMapping

  • HandlerMapping解析请求,根据请求信息和配置信息找到匹配的Controller类

  • 请求参数传递给Controller里的方法

  • 执行完方法后,返回一个ModelAndView,包括视图名称和模型数据

  • 视图解析器根据名称找到视图,渲染后返回给客户端

18、过滤器和拦截器的区别
  • 过滤器在servlet接收到请求之后,但在servlet被调用之前运行

    拦截器在servlet调用之后,但在响应被发送到客户端之前运行

  • 过滤器在web.xml中配置,拦截器在spring配置文件中配置或者使用注解

  • 过滤器依赖于servlet,拦截器不依赖servlet

  • 过滤器只能对request和response操作,拦截器可以对request、response、handler、modelAndView、excepion操作

你可能感兴趣的:(spring,java,后端)