Spring整体结构:
Spring实际运行场景:
基础
Spring启动过程
传统Spring:
(1)初始化准备阶段
(2)容器创建与注入
(3)Bean工厂后置处理
(4)Bean工厂后置处理
(5)Bean实例化与依赖注入
(6)容器启动完成
Spring Boot应用:
(1)启动类触发(@SpringBootApplication)
(2)初始化SpringApplication
(3)环境准备Environment
(4)创建ApplicationContext
(5)自动装配(@EnableAutoConfiguration)
(6)Bean加载与初始化(同传统Spring核心流程)
(7)Bean加载与初始化(同传统Spring核心流程)
(8)Bean加载与初始化(同传统Spring核心流程)
Spring的组成部分
- 核心容器模块:核心包(spring-core)、上下文包(spring-context)、表达式语言包(spring-expression)
- 面向切面编程模块:spring-aop、spring-aspects
- 数据访问/集成模块:spring-jdbc、spring-tx、spring-orm
- web模块:spring-web、spring-webmvc、spring-websocket
- 测试模块:spring-test
Spring的优势
- 轻量级与低侵入性
- 强大的IoC与DI机制
- 面向切面编程AOP
- 丰富的模块支持
- 良好的整合性
- 优秀的社区支持与生态系统
Spring运用了哪些设计模式
- 工厂模式:FactoryBean、BeanFactory和ApplicationContext
- 单例模式:默认Bean的作用域
- 代理模式:AOP的实现(基于JDK和CGLIB实现动态代理)
- 模板方法模式:数据库操作模板(JDBCTemplate、RedisTemplate)
- 观察者模式:事件驱动模型(ApplicationEvent和ApplicationListener)
- 适配器模式:在Spring AOP中用于增强或通知(Advice)的实现。适配不同的Controller实现类
- 装饰器模式:BeanWrapper对Bean的增强(把配置文件中的字符串转换为Bean的属性类型)
- 策略模式:资源加载策略,ResourceLoader通过Resource接口的不同实现(ClassPathResource、FileSystemResource)
IoC
优势:解耦对象依赖、统一管理对象的生命周期、便于扩展与复用、简化测试
DI
DI与IOC的关系:
- IOC是思想:强调“控制权转移”(容器管对象)。
- DI是手段:通过“注入依赖”的方式,实现IOC的思想落地。
简单说:IOC 是“要解决什么问题”,DI 是“具体怎么解决”。
注入方式:构造器注入、Setter注入、字段注入
注入如何解决循环依赖问题(常见问题)
- 三级缓存:
- 一级缓存:用于存储已经初始化完毕的单例Bean实例
- 二级缓存:存储已经实例化但未完成属性注入和初始化的单例Bean实例
- 三级缓存:存储能够生成单例Bean实例的工厂对象
为什么需要三级缓存?(常见问题)
- 依赖注入方式的选择:构造器注入(会造成死锁)、Setter注入
- 其他解决办法:使用@Lazy注解、使用@PostConstruct注解、使用ApplicationContext获取Bean、使用接口和事件机制
Bean
如何创建Bean?
- BeanFactory:核心接口,用于管理和提供Bean实例;
- ApplicationContext:继承BeanFactory,有国际化、资源访问、事件传播等高级特性;
- FactoryBean:接口,存在复杂的初始化流程时使用;
- ObjectFactory:接口,用于延迟获取对象,常作为参数传递。
Bean的作用域(生命周期和可见范围)
- 单例
- 原型
- 请求
- 会话
- 应用
- webSocket会话
Bean的生命周期
- 实例化
- 属性复制
- 初始化前
- 初始化
- 初始化后
- 使用中
- 销毁
单例Bean不一定线程安全怎么办?
- 使用无状态的Bean
- 使用线程安全容器
- 使用同步机制
- ThreadLocal
- 将Scope更改为多例
初始化过程
- Bean定义信息的载入与解析
- Bean的实例化
- 属性填充(依赖注入)
- 执行BeanPostProcessor接口
- Bean的初始化
- Spring Bean的生命周期完整
AOP
实现原理
JDK动态代理、CGLIB动态代理
AOP和AspectJ
- 实现机制:
- Spring AOP:基于动态代理和字节码增强(在运行时通过代理对象或修改字节码来织入切面逻辑),只能在运行时织如切面逻辑,对类的侵入性相对较小。
- AspectJ:是一个完整的AOP框架,提供了丰富的AOP语言支持。它可以通过编译时织入(Compile - time Weaving)、类加载时织入(Load - time Weaving)等方式将切面逻辑织入到目标代码中,功能更强大,能实现更细粒度的切面控制,但对项目的构建过程有一定影响,需要特定的编译器或织入器支持。
- 功能范围:
- Spring AOP:主要关注与Spring应用相关的切面需求,如对Spring Bean的方法进行切面增强,支持的连接点主要是方法调用。
- AspectJ:提供了更广泛的连接点支持,除了方法调用,还包括字段访问、构造函数调用等,能满足更复杂的AOP需求。
- 使用难度:
- Spring AOP:与Spring框架紧密集成,使用Spring的配置或注解(如@Aspect、@Before等)就可以很方便地实现切面功能,对于熟悉Spring的开发者来说容易上手。
- AspectJ: 由于其功能丰富和实现方式的多样性,学习曲线相对较陡,需要开发者对 AOP 概念和 AspectJ 语法有更深入的理解。
术语
- 切面
- 连接点
- 切入点
- 通知(前置通知、后置通知、返回通知、异常通知、环绕通知)
- 目标对象
- 代理
- 织入
事务
4种事务特性:原子性、一致性、隔离性、持久性
5种隔离机制:默认隔离级别、读未提交、读已提交、可重复读、可串行化
7种传播行为:required、supports、mandatory、requires_new、not_supported、never、nested
事务失效场景:
- 方法不是public修饰
- 自调用(内部方法调用)
- 未被Spring容器管理
- 异步被捕获且未重新抛出
- 异步类型不匹配
- 数据源未配置事务管理器
- 多线程调用
注解
- 核心模式与组件定义:
- @Component:标记一个类为Spring组件。
- @Controller:标记一个类为 Spring MVC 控制器组件(是 @Component 的特化)。
- @Service:标记一个类为服务层业务逻辑组件(是 @Component 的特化)。
- @Repository:标记一个类为数据访问层(DAO) 组件(是 @Component 的特化),自带平台特定的异常转换功能。
- @Configuration + @Bean:用于基于Java的配置。@Configuration 标记一个类为配置类,其内部使用 @Bean 标注的方法会定义一个Bean,并交由Spring容器管理。
- 依赖注入与装配:
- @Autowired:用于根据类型(byType)进行自动注入。
- @Qualifier:与 @Autowired 配合使用,当存在多个相同类型的Bean时,通过名称(byName)来指定要注入的具体Bean。
- @Primary:设置一个Bean为首选项。当有多个相同类型的Bean且没有指定 @Qualifier 时,优先注入带有此注解的Bean。
- @Value:用于注入基本数据类型、SpEL表达式或配置文件中的属性值(如 @Value(“${server.port}”))。
- Web MVC相关:
- RequestMapping、@GetMapping、@PostMapping:将HTTP请求映射到特定的控制器方法。
- @RequestBody:将HTTP请求的Body内容(通常是JSON/XML)绑定到方法的参数上。
- @ResponseBody:将方法的返回值直接绑定到HTTP响应体上(通常转换为JSON/XML)。
- @PathVariable:将URL模板变量绑定到方法参数上(如/users/{id})。
- @RequestParam:将请求参数(URL查询参数或表单数据)绑定到方法参数上。
- @ModelAttribute:将请求参数绑定到模型对象上,或用于在方法上提前准备模型数据。
- @RequestHeader:将请求头(Header)的值绑定到方法参数上。
- @CookieValue:将Cookie的值绑定到方法参数上。
- @SessionAttribute:访问预先存在于会话(Session)中的属性。
- @ExceptionHandler:在控制器内部声明一个方法来处理特定类型的异常。
- @ResponseStatus:标记方法或异常类,指定HTTP响应的状态码。
- 数据验证:
- @Validated:Spring提供的注解,用于触发校验,支持分组校验。
- @Valid:Java标准校验注解,通常用于方法参数上触发校验。在Spring中,两者常可互换,但@Validated功能更强大。
- Bean生命周期与作用域:
- @PostConstruct:标注一个方法,在Bean初始化完成后立即执行(类似于init-method)。
- @PreDestory:标注一个方法,在Bean被容器销毁之前执行(类似于destroy-method)。
- @Scope:定义Bean的作用域(如:singleton、prototype、requeest、session等)。
- @Lazy:表示一个Bean是延迟初始化的,只有在第一次被使用时才会创建。
- 配置与条件化:
- @Profile:指定一个Bean或配置类只在特定的环境Profile激活时才会被注册(如:“dev”、“prod”)。
- @Conditional:根据满足某个特定条件(自定义或Spring内置条件,如 @ConditionalOnProperty)才注册Bean,是更通用的条件化注解。
- @PropertySource:指定Spring加载指定的属性文件(.properties 或 .yml)到环境(Environment)中。
- 高级功能:
- @Transactional:声明式事务管理。
- @Cached、@CacheEvict、@CachePut:声明式缓存,用于方法结果的缓存和清除。
- @Scheduled:用于声明一个方法是定时任务,可以基于 cron、固定速率或固定延迟执行。
- @Async:声明一个方法是异步执行的,调用此方法会立即返回,实际执行将提交给TaskExecutor。
- @EventListener:声明一个方法为应用事件监听器,用于监听Spring容器内发布的Application。
Async
内部失效原因:Spring的AOP是基于代理实现的,而内部调用会绕过代理机制。
如何避免内部调用失效?
- 自我注入
- 使用ApplicationContext获取代理对象
- 使用AopContext获取代理对象
- 拆分为单独的服务类
- 手动使用TaskExecutor
什么时候会失效?
- 未使用@EnableAsync注解
- 内部方法调用
- 方法非public
- 方法返回值错误
- 方法用static修饰了
- 方法用final修饰
- 业务类没加@Service注解
- 自己new的对象
- Spring无法扫描异步类
拦截器和过滤器
过滤器和拦截器都是基于AOP思想实现的,用来解决项目中某一类问题的两种工具。
拦截器
拦截器用于请求处理之前或之后执行的某些逻辑。拦截器可以用来实现日志记录、权限检查、性能监控等功能。
过滤器
比较
- 出身不同:过滤器来自Servlet,而拦截器来自于Spring框架。
- 触发时机不同:请求进入容器 > 进入过滤器 > 进入 Servlet > 进入拦截器 > 执行控制器(Controller)。过滤器会先执行,然后才会执行拦截器,最后才会进入真正的要调用的方法。
- 实现不同:过滤器是基于方法回调实现的;拦截器是基于动态代理实现的。
- 支持的项目类型不同:过滤器要依赖 Servlet 容器,它只能用在 Web 项目中;而拦截器是 Spring 中的一个组件,因此拦截器既可以用在 Web 项目中,同时还可以用在 Application 或 Swing 程序中。
- 使用的场景不同:拦截器主要用来实现项目中的业务判断的,过滤器通常是用来实现通用功能过滤的。
JPA和Hibernate
JPA是一套ORM的规范,定义了标准接口和注解
Hibernate是JPA规范的一种实现
Spring Data JPA 则是基于 JPA 规范的进一步抽象和封装
参考
https://chuangshi.qq.com/read/29977156/9