列举一些重要的Spring模块?
- Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IOC 依赖注入功能。
- **Spring Aspects ** : 该模块为与AspectJ的集成提供支持。
- Spring AOP :提供了面向方面的编程实现。
- Spring JDBC : Java数据库连接。
- Spring JMS :Java消息服务。
- Spring ORM : 用于支持Hibernate等ORM工具。
- Spring Web : 为创建Web应用程序提供支持。
- Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
谈谈自己对于 Spring IoC 和 AOP 的理解
IoC
IoC(Inverse of Control:控制反转)而是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IOC 容器来管理,并由 IOC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IOC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。
推荐阅读:https://www.zhihu.com/question/23277575/answer/169698662
Spring IOC的初始化过程:
IOC源码阅读
- https://javadoop.com/post/spring-ioc
AOP
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。
Spring AOP 和 AspectJ AOP 有什么区别?
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
Spring 中的 bean 的作用域有哪些?
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
- global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话
Spring 中的 bean 生命周期?
说说 Spring MVC 有哪些优点?
-
清晰的MVC实现:Spring MVC 提供了一个清晰的模型-视图-控制器(MVC)架构实现,有助于将业务逻辑、用户界面和输入处理分离,使代码更加模块化,易于维护。
-
灵活性:Spring MVC 允许开发者定制几乎每一个组件,从请求到视图的映射,到视图解析器,再到数据绑定和验证机制,都提供了高度的灵活性。
-
强大的数据验证功能:Spring MVC 内置了数据验证功能,支持通过注解或者自定义验证逻辑来进行数据验证,同时可以很好地与错误信息的国际化相结合。
-
文件上传支持:Spring MVC 内置了文件上传的支持,不需要依赖第三方库即可处理文件上传请求。
-
异常处理:Spring MVC 支持通过控制器方法或全局异常处理器来处理异常,这使得错误处理更为集中和一致。
-
请求和响应的灵活处理:Spring MVC 支持多种数据格式(如 JSON 和 XML),并能自动进行序列化/反序列化,这使得与 RESTful 服务交互变得简单。
-
与Spring框架的紧密集成:Spring MVC 作为 Spring 框架的一部分,可以方便地利用 Spring 框架的其他特性,如依赖注入(DI)、面向切面编程(AOP)、事务管理等。
-
社区支持:由于 Spring MVC 是 Spring 框架的一部分,因此它拥有庞大的用户群和活跃的社区支持,这为解决开发过程中遇到的问题提供了便利。
-
测试友好:Spring MVC 设计时考虑到了单元测试的需求,提供了模拟 HTTP 请求的功能,使得编写控制器层的测试变得更加容易。
SpringMVC 工作原理了解吗?
Spring 框架中用到了哪些设计模式?
说几种比较常见的:
Spring 管理事务的方式有几种?
- 编程式事务,在代码中硬编码。(不推荐使用)
- 声明式事务,在配置文件中配置(推荐使用)
声明式事务又分为两种:
- 基于XML的声明式事务
- 基于注解的声明式事务
Spring 事务中的隔离级别有哪几种?
1、读未提交:当前事务读到的数据是别的事务想要修改成为的但是没有修改成功的数据。这时就会产生脏读(读到别人没有提交的数据,造成回滚了)
脏读:所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
2、读已提交:针对 update 或 delete ,在事务处理期间,如果其他事务修改了相应的数据,那么同一个事务的多个 SELECT 语句可能返回不同的结果。在一个事务内,能看到别的事务提交的数据。出现不可重复读。
3、可重复读:针对 insert ,是 MySQL 的默认隔离级别,它确保了一个事务中多个实例在并发读取数据的时候会读取到一样的数据;不过理论上,这会导致另一个棘手的问题:幻读 (通过加锁机制,但新加的数据没有上锁,就会出现幻读)
解决办法:InnoDB 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决幻读。
幻读:事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
4、可串行化:就是一个一个来,性能最慢
Spring 事务中哪几种事务传播行为?
传播属性 | 说明 |
PROPAGATION_REQUIRED【required [rɪ'kwaɪəd]】 【 propagation [ˌprɒpə'ɡeɪʃ(ə)n] 】 | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS 【support [səˈpɔrt]】 | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY 【mandatory [ˈmændəˌtɔri] 】 | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW 【 requires_new 】 | 新建事务,如果当前存在事务,把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED 【 supported 】 | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER 【 never 】 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED 【 nested 】 | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。 |