什么是Spring?谈谈你对IOC和AOP的理解。

Spring是一种Java开发框架,旨在简化企业级应用程序的开发和部署。它具有以下优点:

  1. 对象托管:Spring能够管理和赋值所有对象,使开发人员不再需要手动管理对象的创建和依赖关系。
  2. 动态代理:Spring的动态代理功能可以实现大部分可复用的逻辑功能,从而避免了重复的代码。
  3. 强大的框架生态系统:市面上几乎所有的框架都是基于Spring构建的,Spring提供了强有力的支持和集成能力。
  4. 低侵入性:Spring的代码对于我们的应用代码几乎是无侵入的,只需要使用几个注解就能让Spring启动。

控制反转(IoC)是Spring的一个重要特性,它使得对象的创建和依赖关系的管理由Spring容器来完成。IoC有三种实现方式:注解形式、构造器形式和set方法注入。通过IoC,我们不再需要使用new关键字手动创建对象,而是将对象的创建和管理交给Spring容器处理。

面向切面编程(AOP)是Spring的另一个重要特性,它通过动态代理实现。AOP常用于日志收集、事务管理等方面。通过AOP,我们可以在被代理对象的方法执行前后,加入一些统一的业务逻辑处理,例如日志记录或权限校验。

Spring容器的启动流程是怎么样的?

启动流程几乎跟源码息息相关,如果没有看过源码可能对启动流程只能靠自己的理解去背,如果对源码右深入理解,那么这道题可以这么说:

1:初始化reader和scanner

2:使用scanner组件扫描basePackage下的所有对象,将配置类的BeanDefinition注册到容器中。

3:refresh(); 刷新容器。

可以分为以下几个步骤:

  • 定位配置文件:Spring容器首先需要定位配置文件的位置和名称。可以通过ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等类来指定配置文件的路径。
  • 加载配置文件:Spring容器会读取配置文件的内容,并将其转换为内部的数据结构,一般使用DOM或SAX解析XML文件。
  • 创建容器对象:根据配置文件中的定义,Spring容器会创建一个或多个容器对象。常用的容器对象是ApplicationContext和BeanFactory。ApplicationContext是BeanFactory的子接口,提供了更多的功能。
  • 注册Bean定义:Spring容器会解析配置文件中的Bean定义,包括Bean的名称、类型、依赖关系等,并将其注册到容器中。这些Bean定义会被封装为BeanDefinition对象。
  • 实例化Bean:根据注册的Bean定义,Spring容器会实例化相应的Bean对象,并将其放入容器中管理。实例化可以通过构造方法、工厂方法或者通过AOP代理来完成。
  • 注入依赖:Spring容器会根据Bean定义中的依赖关系,将相应的依赖注入到Bean中。可以通过构造方法、setter方法或者注解方式来完成注入。
  • 调用初始化方法:如果Bean定义中指定了初始化方法,Spring容器会在实例化和依赖注入完成后,调用Bean的初始化方法。可以通过配置文件或者注解指定初始化方法。
  • 容器就绪:当所有的Bean都被实例化、注入依赖并初始化完成后,Spring容器就处于就绪状态,可以提供相应的服务。

然后在细说自己知道的部分源码,比如我还了解到一些关于源码的细节。例如,在获取Bean定义后,Spring会在实例化之前通过合并Bean定义来进行初始化,并且AOP的逻辑是在初始化之后通过后置处理器进行动态代理。

此外,如果我们需要监听Spring的启动过程以及在启动后实现自己的业务逻辑,除了可以使用初始化对象的方法afterPropertiesSet外,还可以通过注册一个监听器来监听Spring发布的各种事件。这样,我们就可以在特定的事件触发时执行我们自己的逻辑。

Spring框架中Bean的创建过程是怎样的?

在Spring框架中,Bean的创建过程涉及到多个环节和细节。下面我将更详细地介绍每个步骤的具体内容。可以大致分为五个步骤:获取Bean定义、实例化、赋值、初始化和销毁。

  1. Bean定义是在包扫描的过程中进行注册的。通过扫描配置文件或使用注解等方式,将Bean的定义信息注册到Spring容器中。
  2. 根据Bean定义进行实例化。这一步骤会根据Bean的构造器创建对象实例,如果没有指定构造器,则使用默认的构造器。在实例化过程中,还可以应用前后实例化处理器对对象进行一些额外的处理。
  3. 在赋值阶段,会对Bean中的依赖进行赋值。这可以通过使用@Autowired注解注入依赖属性来实现。赋值完成后,Bean的属性就可以访问到依赖的对象。
  4. 通过调用init-method(@PostConstruct)方法或实现InitializingBean接口(afterPropertiesSet)来进行初始化操作。在初始化过程中,可以执行一些特定的逻辑,例如数据加载等。同样地,也可以应用前后初始化处理器对Bean进行一些额外的处理。
  5. 销毁阶段是在应用程序关闭或需要销毁Bean时执行的。通过调用destroy-method方法(@PreDestroy),可以执行对象的销毁逻辑,DisposableBean: 当Bean实现了这个接口,在对象销毁前就会调用destory()方法。

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

Spring框架中的Bean默认是单例模式,因此不是线程安全的。如果要处理线程安全问题,可以采取以下几种方式:

  • 使用prototype作用域:通过将Bean的作用域设置为prototype,确保每次请求都创建一个新的对象,从而保证线程安全。
  • 避免使用全局资源属性:尽量避免在Bean中使用全局资源属性,而是使用无状态的属性,比如使用注解形式的Bean注入。
  • 使用ThreadLocal类:可以使用ThreadLocal类将属性与线程进行绑定,确保每个线程独有一份属性副本,从而避免线程安全问题。

Spring如何处理循环依赖问题?

大家都知道spring采用的是三级缓存,那么如何理解三级缓存处理了循环依赖问题呢?

一级缓存:缓存最终的单例池对象: private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

二级缓存:缓存初始化的对象:private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

三级缓存:缓存对象的ObjectFactory: private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

其实当一个对象实例化后就会存储在 singletonFactories三级缓存,当被引用时,会执行一个后置处理器方法,这里也是给aop创建代理对象的时机:

  protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}

如果是正常的普通对象,会直接进行如二级缓存,并返回一个实例化后的对象,所以之所以使用到了三级缓存,而不是光是用二级缓存就是考虑到了循环依赖可能是一个代理对象,我们无法直接提供实例化的对象而是一个代理对象。

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

Spring如何处理事务?

Spring框架提供了两种方式来处理事务:编程式事务和声明式事务。

编程式事务是通过使用TransactionTemplate来进行事务管理的方式。它需要手动在代码中显式地指定事务的开启、提交和回滚操作。这种方式对代码的侵入性较高,因为需要在每个需要进行事务管理的方法中编写事务处理的代码。一般情况下,不推荐使用编程式事务,除非在特定的场景下需要对事务进行更精细的控制。

声明式事务是通过使用注解或XML配置的方式来声明事务的行为。在Spring中,最常用的是使用注解来声明事务。通过在方法或类上添加@Transactional注解,可以指定事务的传播行为、隔离级别、超时时间等属性。事务的传播行为指的是当一个方法调用另一个带有事务注解的方法时,事务应该如何进行传播和管理。

Spring框架提供了以下几种事务的传播级别:

  • REQUIRED(默认值):如果当前存在事务,则加入该事务,如果不存在事务,则创建一个新的事务。
  • REQUIRES_NEW:无论当前是否存在事务,都创建一个新的事务。如果当前存在事务,则将当前事务挂起。
  • SUPPORTS:如果当前存在事务,则加入该事务,如果不存在事务,则以非事务方式执行。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。
  • MANDATORY:当前必须存在事务,否则抛出异常。
  • NEVER:当前不能存在事务,否则抛出异常。
  • NESTED:如果当前存在事务,则在一个新的嵌套事务中执行。如果不存在事务,则执行与REQUIRED一样的操作。

Spring框架提供了以下几种事务的隔离级别:

  • READ_UNCOMMITTED(读未提交):此级别最低,允许读取其他事务尚未提交的数据,可能会读取到脏数据。
  • READ_COMMITTED(读已提交):在一个事务内,只能读取到已经提交的数据,避免了脏数据,但是可能会产生幻读。
  • REPEATABLE_READ(可重复读):在一个事务内,多次读取同一数据结果保持一致,解决了幻读的问题。
  • SERIALIZABLE(串行化):最高的隔离级别,所有事务都是串行执行,避免了并发问题,但并发度最低。

SpringMVC中的控制器是不是单例模式?如果是,如何保证线程安全?

在Spring MVC中,默认情况下,控制器是以单例模式创建的。这意味着在应用程序的整个生命周期中,只会创建一个控制器实例来处理所有的请求。为了保证控制器的线程安全性,可以采取以下措施:

1:保持控制器的无状态属性:控制器应该尽量避免使用实例变量来保存状态信息,尽量使用方法参数或局部变量来处理请求。这样可以确保每个请求都有独立的数据副本,避免多个线程之间的竞争和冲突。

2:设置控制器的作用域为非单例模式:可以将控制器的作用域设置为非单例模式,如prototype或request。这样每次请求都会创建一个新的控制器实例,确保每个请求都有独立的控制器对象,避免线程安全问题。

总结

本次面试涉及了Spring框架的多个方面,包括IOC和AOP的理解、Spring容器的启动流程、Bean的创建过程、Bean的线程安全性、循环依赖的处理、事务的处理以及Spring MVC中控制器的线程安全性。通过这些问题的回答,展示了对Spring框架的深入理解和应用经验。同时,也凸显了对面试题目的认真思考和清晰表达的能力。

Spring面试攻略:如何展现你对Spring的深入理解的更多相关文章

  1. IOS面试攻略

    IOS面试攻略(1.0) 2013-10-13 20:58:09|  分类: IOS面试 |  标签:ios知识点总汇  ios面试  |举报|字号 订阅     来自:伊甸网 @ 看到这个关键字,我 ...

  2. oc面试攻略

    原文出自:http://mobile.51cto.com/iphone-402619.htm 1.Object-C有多继承吗?没有的话用什么代替?cocoa 中所有的类都是NSObject 的子类 多 ...

  3. Spring Cloud Consul 之Greenwich版本全攻略

    什么是Consul Consul是HashiCorp公司推出的开源软件,使用GO语言编写,提供了分布式系统的服务注册和发现.配置等功能,这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全 ...

  4. Spring Boot Admin 2.1.0 全攻略

    转载请标明出处: https://www.fangzhipeng.com 本文出自方志朋的博客 Spring Boot Admin简介 Spring Boot Admin是一个开源社区项目,用于管理和 ...

  5. 【JAVA EE企业级开发四步走完全攻略】

    本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划,单个发blog比较零散,所以整理此索引,决定以后每发一季JAVA EE blog后会 ...

  6. 17个经典的Spring面试问答

    Q1.什么是Spring Framework? Spring是Java企业版应用程序开发中使用最广泛的框架.Spring的核心功能可用于开发任何Java应用程序. 我们可以使用它的扩展来在Java E ...

  7. 图文详解:阿里宠儿【小兔】RabbitMQ的养成攻略

  8. 从小工到专家 ——读《Java程序员职场全攻略》有感

    从小工到专家 ——读<Java程序员职场全攻略>有感   <Java程序员职场全攻略>是以故事的形式,向读者介绍Java程序员的职场经验.作者牛开复在北京从事软件开发,已经是一 ...

  9. JAVA EE企业级开发四步走完全攻略 [转]

    http://bbs.51cto.com/thread-550558-1.html 本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划, ...

  10. 【转】Perl Unicode全攻略

    Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...

随机推荐

  1. 2020-09-24:jvm监控系统是通过jmx做的么?

    福哥答案2020-09-24:#福大大架构师每日一题# [此答案来自知乎:](https://www.zhihu.com/question/422632973) 一般都是,但是要是记录比较详细的性能定 ...

  2. 【GiraKoo】常用编码的对比(ASCII,GB2312,GBK,GB18030,UCS,Unicode)

    常用编码的对比(ASCII,GB2312,GBK,GB18030,UCS,Unicode) 在程序开发中,文字编码一直扮演着人畜无害,却背后捅一刀的角色. 可能在源代码文件中,注释莫名其妙地变成了乱码 ...

  3. 《Just For Fun》:学习即游戏

    <Just For Fun>:学习即游戏 最近读完了 Linus 的自传<Just For Fun>,一直想写点东西,但始终苦于工作繁忙,无暇思考该从何写起.技术上自然不用废话 ...

  4. 数据科学工具 Jupyter Notebook 教程(一)

    ipython notebook 是一个基于浏览器的 python 数据分析工具,使用起来非常方便,具有极强的交互方式和富文本的展示效果.jupyter 是它的升级版,它的安装也非常方便,一般 Ana ...

  5. 【C#/.NET】record介绍

    ​  目录 什么是record? 使用record record解构 record原理 结论 什么是record? record是.NET 5中的一种新特性,可以看作是一种概念上不可变的类.recor ...

  6. OSPF路由控制

    实验拓扑 实验需求 公司A使用OSPF路由协议实现公司设备全网互通,后来公司A扩张兼并了公司B,要求将公司B采用的IS-IS路由协议与公司A的OSPF协议互相引入,使得相应部门可以实现互通. Rout ...

  7. 做副业的我很迷茫,但ChatGPT却治好了我——AI从业者被AI模型治愈的故事

    迷茫,无非就是不知道自己要做什么,没有目标,没有方向. 当有一个明确的目标时,往往干劲十足.但做副业过程中,最大的问题往往就是 不知道自己该干什么. 干什么?怎么干?干到什么程度?这是做副业(甚至任何 ...

  8. JUC同步锁原理源码解析三----CountDownLatch、CyclicBarrier

    JUC同步锁原理源码解析三----CountDownLatch.CyclicBarrier CountDownLatch.CyclicBarrier的来源 1.CountDownLatch的来源 A ...

  9. Cause: org.apache.ibatis.builder.BuilderException: Ambiguous collection type for property 'emps'. You must specify 'javaType' or 'resultMap'

    错误原因 这个错误通常表示在解析 Mybatis 映射文件(Mapper XML)时出现了问题,可能的原因有两个: 集合属性缺少 javaType 或 resultMap 属性:该错误信息显示了 &q ...

  10. redis集群报错:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk.

    之前在x86架构的服务器部署redis集群,未遇到题中问题:然而在ARM架构的服务器部署redis集群,第一次遇到如此问题.虽然问题已经解决,但不清楚问题的具体原因,在此做个记录. 性能测试过程中,通 ...