Spring IOC

是spring的两大重要特性,IOC就是控制反转、注入依赖么。他就是Spring将我们的类通过注解的方式,将他的创建和生命周期都放到Spring容器中统一管理,这样我们其他的类如果需要调用某个类就可以直接到Spring的容器工厂中去找。spring也提供了很多注解能让我们之间注册bean到容器中,以及注入使用的注解。

什么是Spring

Spring是Java开发框架,通过可扩展的模型来开发Java应用程序,Spring的核心包括依赖注入和控制反转、面向切面编程、声明式事务、MVC框架等;Spring框架的核心是Spring容器,它负责管理应用程序中的对象,容器使用依赖注入来自动注入依赖项。

依赖注入和控制反转:将对象的创建和管理反转到Spring容器当中,容器根据配置和文件来帮助创建对象和维护依赖关系,通过依赖注入实现,当在容器中创建对象A的时候,发现标注依赖了B,就会将B创建出来塞到A里面。使得代码解耦,并且更容易进行单元测试和集成测试

面向切面编程:可以将通用的横切关注点(日志记录,事务管理)从代码中分离出来,提高了应用程序的可维护性和扩展性

MVC框架:使得我们可以轻松的构建一个WEB应用

依赖注入的方式

Spring支持三种依赖注入方式:

  1. 构造函数注入:通过在构造函数中声明需要注入的依赖项,容器创建对象时会自动将依赖项注入到构造函数中

    • 优点:保证依赖不可变、保证对象初始化完成、适合必需依赖
    • 缺点:参数较多时构造函数臃肿
  2. Setter注入:通过在类中声明Setter方法,并在方法中传入需要注入的依赖项,对象创建的时候会调用方法注入依赖项

    • 优点:灵活、可选依赖、可以随时修改
    • 缺点:无法保证对象初始化完成
  3. 字段注入:通过在类中通过注解标明需要注入的依赖项的字段,容器在创建后自动注入依赖项

    • 优点:代码简洁
    • 缺点:无法设置final、不推荐使用、容易NPE

推荐使用构造函数注入,对于可选依赖可以使用Setter注入。

Spring AOP

AOP就是IOC的一个扩展,他是面向切面编程,其实就是一个动态代理,通常情况他的作用就是能实现我们非业务的代码,不去影响实际的业务,其实就是在不动已经完成的业务代码,想要在加上非业务的代码的时候会用到AOP思想,比如要看日志,算接口时间,事务管理等。
比如有一个user类,我想在它的add方法前后增加日志,通过AOP,Spring并不会入侵代码,而是创建一个和user类一模一样的代理对象,以后调用的其实是这个代理对象,代理对象会先执行日志任务再调用真正的user类中的add方法。Spring 会根据目标对象的类型,自动选一种代理方式:第一种是JDK动态代理,目标对象有接口时用,比如UserService实现了IUserService接口,Spring 就用 JDK 自带的工具生成一个实现了IUserService接口的代理类
这个代理类里会持有真正的UserService对象,当你调用addUser()时,代理类会先跑日志代码,再调用UserServiceaddUser()
第二个是CGLIB动态代理,目标对象无接口的时候,Spring 就用 CGLIB 生成一个继承UserService的子类当代理,子类会重写addUser()方法,在重写的方法里先执行日志逻辑,再调用父类(真正的UserService)的addUser()

循环注入和循环依赖

循环依赖是指两个或多个Bean之间相互依赖,形成一个环形依赖。Spring通过三级缓存来解决循环依赖问题:

  • 一级缓存(singletonObjects):存放完全初始化好的单例Bean
  • 二级缓存(earlySingletonObjects):用于存储实例化完成但初始化未完成的Bean
  • 三级缓存(singletonFactories):存储的工厂对象,用于生成Bean的代理对象或原始对象

注意:Spring只能解决单例Bean的Setter注入的循环依赖,构造函数注入的循环依赖会直接抛出异常。

Bean的生命周期

IOC的加载其实就是一个Bean的创建么,Bean从创建到销毁就是它的生命周期,首先是类实例化,它是通过反射去找类的构造函数实例化的。再属性赋值,解析自动装配的,一般用@autowired或者@resource,解决了循环依赖的问题。接着是初始化,初始化的时候调用初始化生命周期回调,这个时候就可以使用该类了,最后容器关闭的时候,调用销毁生命周期回调,将Bean进行一个销毁处理。

Spring 的自动装配过程如何识别要装配的类?会扫描全部类吗?

Spring 识别要装配的类主要通过 组件扫描(Component Scan),而非扫描项目中的全部类,具体逻辑如下:他会扫描spring用注解标记的一些类,将标记的类注册为 Bean。开发者需在配置中指定扫描的包路径(如@ComponentScan("com.example")),Spring 仅扫描该路径下的类,不会扫描所有类,以此提升效率。

Spring Boot 自动配置原理?

  1. 注解驱动@SpringBootApplication 包含 @EnableAutoConfiguration,触发自动配置;
  2. SPI 机制:Spring 扫描 META-INF/spring.factories,加载所有 AutoConfiguration 类;
  3. 条件装配:通过 @Conditional(如 @ConditionalOnClass@ConditionalOnBean)判断环境是否满足,满足则自动创建 Bean。

@Component和@Bean

首先在用途方面和使用方法不同,Component注解是标识普通的类,spring会通过Componentscan扫描将类注册到spring IOC容器中。@bean一般是在配置类中的方法,声明和手动配置一个bean对象。Component注解是spring自动创建和初始化的,bean注解可以手动控制bean的创建和配置过程

@autowired和@resource

@Autowired 是 Spring 框架提供的注解,默认按类型(byType)注入,若存在多个同类型 bean,需配合 @Qualifier 指定名称;而 @Resource 是 JDK 提供的注解,默认按名称(byName)注入,名称匹配失败时会 fallback 到按类型匹配。Resource支持属性配置可以配置name type等

Spring中用到的设计模式

Spring框架中使用了多种设计模式:

  1. 工厂模式:BeanFactory和ApplicationContext是工厂模式的实现,用于创建和管理Bean对象
  2. 单例模式:Spring Bean默认是单例的,通过Spring容器保证唯一性
  3. 代理模式:AOP的核心就是代理模式,通过JDK动态代理或CGLIB代理实现
  4. 模板方法模式:JdbcTemplate、RestTemplate等使用了模板方法模式,将不变的部分封装在父类,可变的部分留给子类实现
  5. 观察者模式:ApplicationEvent和ApplicationListener实现了事件监听机制
  6. 适配器模式:HandlerAdapter等使用了适配器模式,将不同的接口适配成统一的接口

Bean的作用域

Spring Bean支持多种作用域:

  1. singleton(单例):默认作用域,整个容器中只有一个Bean实例
  2. prototype(原型):每次获取Bean时都创建一个新的实例
  3. request:每个HTTP请求创建一个Bean实例,仅在Web应用中有效
  4. session:每个HTTP Session创建一个Bean实例,仅在Web应用中有效
  5. application:ServletContext生命周期,仅在Web应用中有效

默认使用singleton作用域,对于有状态的Bean应该使用prototype作用域。

对Spring的AOP理解

AOP(Aspect-Oriented Programming)面向切面编程是一种编程思想,它将通用的横切关注点(如日志、事务、权限等)从业务逻辑中分离出来。

AOP的核心概念

  1. 切面(Aspect):横切关注点的模块化,比如日志切面、事务切面
  2. 连接点(Join Point):程序执行的某个特定位置,比如方法调用、异常处理
  3. 切点(Pointcut):匹配连接点的表达式,定义在哪里应用通知
  4. 通知(Advice):在切点执行的动作,比如前置通知、后置通知、环绕通知
  5. 织入(Weaving):将切面应用到目标对象并创建代理对象的过程
  6. 目标对象(Target Object):被通知的对象

AOP的实现方式

Spring AOP通过动态代理实现:

  • JDK动态代理:目标对象实现了接口,使用JDK动态代理
  • CGLIB代理:目标对象没有实现接口,使用CGLIB生成子类代理

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

Spring框架中的单例Bean本身不是线程安全的,但Spring容器通过依赖注入来管理Bean,对于无状态的Bean(比如Service、DAO),它们是线程安全的。对于有状态的Bean,Spring提供了以下解决方案:

  1. 使用ThreadLocal:将状态存储在ThreadLocal中,每个线程都有自己独立的副本
  2. 使用原型作用域:将Bean的作用域设置为prototype,每次获取都创建新实例
  3. 使用同步锁:通过synchronized或Lock保证线程安全,但会影响性能
  4. 使用并发容器:比如ConcurrentHashMap、CopyOnWriteArrayList等

建议尽量设计无状态的Bean,避免线程安全问题。

对Spring事务的理解

Spring事务是基于AOP实现的声明式事务管理,它将事务管理从业务代码中分离出来,通过注解或XML配置的方式管理事务。

Spring事务的特性

  1. ACID特性:原子性、一致性、隔离性、持久性
  2. 事务管理器:DataSourceTransactionManager、JtaTransactionManager等
  3. 事务传播:定义了多个事务方法相互调用时的行为
  4. 事务隔离级别:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE

@Transactional注解

@Transactional可以标注在类或方法上,用于开启事务管理。常用的属性包括:

  • propagation:事务传播行为
  • isolation:事务隔离级别
  • timeout:事务超时时间
  • readOnly:是否只读事务
  • rollbackFor:指定哪些异常回滚事务
  • noRollbackFor:指定哪些异常不回滚事务

Spring事务什么情况下会失效

Spring事务在某些情况下会失效,需要注意:

  1. 方法不是public:@Transactional只能作用在public方法上,private、protected方法会失效
  2. 方法内部调用:同一个类中,一个事务方法调用另一个事务方法,内部调用的方法事务会失效
    • 解决:将方法拆分到不同的Bean中,或者通过注入自身调用代理对象的方法
  3. 异常处理不当:默认只回滚RuntimeException和Error,如果抛出CheckedException且没有指定rollbackFor,事务不会回滚
    • 解决:指定@Transactional(rollbackFor = Exception.class)
  4. 数据库引擎不支持事务:比如MySQL的MyISAM引擎不支持事务
  5. 未被Spring管理:如果类没有被Spring容器管理(比如通过new创建的对象),事务会失效
    • 解决:确保类是通过Spring容器获取的

事务的传播机制

事务的传播机制定义了多个事务方法相互调用时的行为,Spring定义了7种传播行为:

  1. REQUIRED(默认):如果当前存在事务,则加入该事务;如果没有事务,则创建一个新事务
  2. SUPPORTS:如果当前存在事务,则加入该事务;如果没有事务,则以非事务方式执行
  3. MANDATORY:如果当前存在事务,则加入该事务;如果没有事务,则抛出异常
  4. REQUIRES_NEW:创建一个新事务,如果当前存在事务,则挂起当前事务
  5. NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
  6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常
  7. NESTED:如果当前存在事务,则在嵌套事务中执行;如果没有事务,则创建一个新事务

Spring MVC的执行流程

Spring MVC的执行流程如下:

  1. 用户发送请求:用户通过浏览器发送HTTP请求到服务器
  2. DispatcherServlet接收请求:前端控制器DispatcherServlet接收请求,它是Spring MVC的核心
  3. HandlerMapping映射处理器:DispatcherServlet调用HandlerMapping,根据请求URL找到对应的Handler(Controller方法)
  4. HandlerAdapter执行处理器:DispatcherServlet调用HandlerAdapter,执行Controller方法
  5. Controller处理业务逻辑:Controller调用Service层处理业务逻辑,返回ModelAndView
  6. ViewResolver解析视图:DispatcherServlet调用ViewResolver,根据视图名称解析出具体的View
  7. 渲染视图:View将Model数据渲染到页面(比如JSP、Thymeleaf等)
  8. 返回响应:将渲染好的页面返回给用户
1
2
3
4
5
6
7
8
9
用户请求 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller

Service层处理业务逻辑

返回ModelAndView

ViewResolver解析视图

渲染视图返回响应

Spring Boot自动配置

为什么使用Spring Boot

Spring Boot简化了Spring应用的初始搭建和开发过程,提供了开箱即用的默认配置:

  1. 简化配置:自动配置Spring应用,减少XML配置
  2. 内嵌服务器:内嵌Tomcat、Jetty等服务器,无需部署WAR包
  3. 自动依赖管理:通过starter简化依赖配置
  4. 生产就绪:提供监控、健康检查等生产级特性
  5. 快速开发:提高开发效率,快速搭建微服务应用

Spring Boot自动装配原理

Spring Boot自动装配的核心是:

  1. 注解驱动:@SpringBootApplication包含@EnableAutoConfiguration,触发自动配置
  2. SPI机制:Spring扫描META-INF/spring.factories,加载所有AutoConfiguration类
  3. 条件装配:通过@Conditional(如@ConditionalOnClass、@ConditionalOnBean)判断环境是否满足,满足则自动创建Bean
  4. 配置绑定:通过@ConfigurationProperties将配置文件中的属性绑定到Bean

Spring Boot常见注解

  1. @SpringBootApplication:启动类注解,包含@Configuration、@EnableAutoConfiguration、@ComponentScan
  2. @RestController:组合了@Controller和@ResponseBody,用于RESTful接口
  3. @RequestMapping:映射HTTP请求到Controller方法
  4. @GetMapping、@PostMapping:GET、POST请求的快捷映射
  5. @Autowired:自动注入依赖
  6. @Component:标识一个组件,被Spring容器管理
  7. @Configuration:标识配置类
  8. @Value:注入配置文件中的属性

Spring Boot开启事务

Spring Boot默认已经开启事务管理,只需在Service层方法上添加@Transactional注解即可:

1
2
3
4
5
6
7
@Service
public class UserService {
@Transactional
public void saveUser(User user) {
// 业务逻辑
}
}

过滤器和拦截器

过滤器(Filter):Servlet规范的一部分,可以拦截请求和响应,主要用于字符编码、跨域处理等

拦截器(Interceptor):Spring MVC特有的,可以访问Controller和Model,主要用于权限控制、日志记录等

区别:

  1. 拦截器基于Java的反射机制,过滤器基于函数回调
  2. 拦截器不依赖Servlet容器,过滤器依赖Servlet容器
  3. 拦截器只能对Controller请求起作用,过滤器可以对几乎所有请求起作用
  4. 拦截器可以访问IOC容器中的Bean,过滤器不能

Spring Boot和Spring MVC的区别

  1. Spring MVC:是Spring框架的一个模块,提供Web MVC功能
  2. Spring Boot:是基于Spring的快速开发框架,默认集成了Spring MVC

Spring Boot简化了Spring MVC的配置,提供了自动配置和starter依赖。

跨域问题

跨域是浏览器同源策略限制,Spring Boot解决跨域的方式:

  1. @CrossOrigin注解:在Controller或方法上添加@CrossOrigin注解
  2. 全局配置:实现WebMvcConfigurer接口,添加CorsMapping
  3. Nginx反向代理:通过Nginx配置反向代理解决跨域

MyBatis

#{}和${}的区别

  1. #{}:预编译SQL,使用占位符,可以防止SQL注入,传入的是参数值
  2. ${}:字符串拼接,直接替换SQL片段,不能防止SQL注入,传入的是字段名或表名

推荐使用#{},只有在动态表名或字段名时才使用${}。

MyBatis动态SQL

MyBatis提供了多种动态SQL标签:

  1. if:条件判断
  2. choose/when/otherwise:多条件选择
  3. trim/where/set:处理SQL拼接问题
  4. foreach:循环遍历集合

SSM

Spring + Spring MVC + MyBatis 三个框架的组合,是 Java 企业级开发中经典的 Web 应用架构。这三个框架各司其职,共同构成了一个完整的分层开发体系:

  • Spring:负责全局管理(IoC 容器、AOP 切面)和组件协调
  • Spring MVC:作为表现层框架,处理 HTTP 请求和响应;
  • MyBatis:作为数据访问层框架,简化数据库操作。