1、什么是Spring框架?
- Spring :是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性
2、Spring、SpringMVC和SpringBoot的区别
- Spring主要指Spring Framework,就是指如上图所示的各项功能模块
- SpringMVC主要指一种架构,MVC分别是Model模型、View视图、Controller控制器的简写,核心思想就是将数据、显示和业务逻辑分离来组织代码。
- SpringBoot旨在简化Spring开发,减少各种麻烦的配置文件,尽量做到开箱即用
3、Spring IoC
- IoC:(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理
- 控制:指的是对象创建(实例化、管理)的权力
- 反转:控制权交给外部环境(Spring 框架、IoC 容器)
- 简单来说,就是将对象的创建、依赖注入等操作交给Spring容器处理,而不是在应用程序中手动创建和管理对象。
- 在传统的应用程序中,对象之间的依赖关系通常是通过手动创建对象、调用构造方法或者工厂类来完成的。这种方式会导致应用程序的代码与具体的实现细节耦合在一起,难以进行单元测试和维护,而且代码的可读性和可复用性也比较差。
- 而使用Spring的IOC容器,可以将对象之间的依赖关系从应用程序代码中抽离出来,通过XML配置或者注解方式来描述对象之间的关系,由Spring容器自动创建和管理对象。这样可以有效地降低应用程序的耦合度,提高代码的可读性和可维护性,同时也方便单元测试和扩展。
4、Spring Bean
1、简介
- 简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象
- 当我们使用Spring框架时,我们需要将Java对象交给Spring容器进行管理,这些对象就被称为Spring Bean。Spring容器会负责创建、配置和管理这些Bean,以及将它们注入到其他Bean中。
- Bean对象的创建和管理是基于IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)的思想实现的。
- 我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类
- SpringBean默认下是单例模式
2、将类声明为Bean的常用注解如下
- @Component :通用的注解,可标注任意类为 Spring 组件
- @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作
- @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层
- @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面
- @Bean:常和@Configuration注解搭配使用,用于显式声明单个bean,而不是让Spring像上面一样自动执行,可以更精细地自定义配置;一般用来注解方法,但其返回值是对象
3、注入Bean的常用注解如下
- @Autowired:Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)
- @Resource:@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType
4、Bean的生命周期
- Bean 容器找到配置文件中 Spring Bean 的定义,Bean 容器利用 Java Reflection API 创建一个 Bean 的实例
- 如果涉及到一些属性值 利用 set()方法设置一些属性值
- 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入 Bean 的名字
- 与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法
- 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
- 如果 Bean 实现了InitializingBean接口,执行afterPropertiesSet()方法
- 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法
- 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
- 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法
- 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法
总结起来,Spring的生命周期其实就是四个过程:实例化、属性赋值、初始化前后、销毁前后
- 实例化:第 1 步,实例化一个 bean 对象;
- 属性赋值:第 2 步,为 bean 设置相关属性和依赖;
- 初始化:第 3~7 步,步骤较多,其中第 5、6 步为初始化操作,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,该阶段结束,才能被用户使用;
- 销毁:第 8~10步,第8步不是真正意义上的销毁(还没使用呢),而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 bean 时再执行相应的方法。
5、Spring AOP
1、简述:AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性,其实现原理就是动态代理
2、相关知识点
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知之后创建的代理对象
- 连接点(JoinPoint):目标对象的所属类中,定义的所有方法均为连接点
- 切入点(Pointcut):被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
- 通知(Advice):增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情
- 切面(Aspect):切入点(Pointcut)+通知(Advice),一个切面就是一个代理对象= 要为哪些类生成代理+要添加的额外功能是哪些
- Weaving(织入):将通知应用到目标对象,进而生成代理对象的过程动作
6、Spring AOP和AspectJ AOP有什么区别?
- Spring AOP 属于运行时增强,而 AspectJ 是编译时增强
- Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)
- Spring AOP相对简单,但AspectJ性能更好
7、AspectJ定义的通知类型
- Before(前置通知):目标对象的方法调用之前触发
- After (后置通知):目标对象的方法调用之后触发
- AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
- AfterThrowing(异常通知) :目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值
- Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法
8、控制多个切面的执行顺序
- 通常使用@Order注解直接定义切面顺序
// 值越小优先级越高
@Order(3)
@Component
@Aspect
public class LoggingAspect implements Ordered {
- 实现Ordered接口重写getOrder方法
@Component
@Aspect
public class LoggingAspect implements Ordered {
// ....
@Override
public int getOrder() {
// 返回值越小优先级越高
return 1;
}
}
9、Spring事务
事务是逻辑上的一组操作,要么都执行,要么都不执行
1、Spring管理事务的方式
- 编程式事务 : 在代码中硬编码(不推荐使用) : 通过 TransactionTemplate或者 TransactionManager 手动管理事务,实际应用中很少使用,但是对于理解 Spring 事务管理原理有帮助
- 声明式事务 : 在 XML 配置文件中配置或者直接基于注解(推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)
2、事务传播行为:为了解决业务层方法之间互相调用的事务问题,@Transactional注解默认使用的值为TransactionDefinition.PROPAGATION_REQUIRED
3、事务的隔离级别:指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题
- 脏读:一个事务读到另一个事务未提交的更新数据。
- 幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
- 不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读
Spring默认的隔离级别是default,表示使用使用数据库默认的隔离级别,数据库隔离级别如下
- MySQL 默认的隔离级别是 REPEATABLE_READ (可重复读)
- Oracle 默认的隔离级别是 READ_COMMITTED (读已提交)
4、@Transactional(rollbackFor = Exception.class)注解:如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚
- 在 @Transactional 注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚
- 加上 rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚
十、实体之间的关联关系注解
- @OneToOne : 一对一
- @ManyToMany :多对多
- @OneToMany : 一对多
- @ManyToOne :多对一
十一、拦截器和过滤器有什么区别
- 实现原理不同:过滤器是基于函数回调实现的,而拦截器则是基于Java的反射机制(动态代理)实现的
- 触发时机不同:Filter只在Servlet前后起作用,而拦截器能够深入到方法前后,异常抛出前后等,因此拦截器的使用具有更大的弹性
- 使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器是一个Spring组件,不仅能在Web程序中使用,也可以用于Application、Swing等程序中。
- 使用场景不同:拦截器主要用来实现项目中的业务来判断的,比如:登录判断、权限判断、日志记录等业务;而过滤器通常是用来实现通用功能过滤的,比如:敏感词过滤、字符集编码设置等。