Spring相关
2025-02-09 22:17:11 0 举报
AI智能生成
spring相关
作者其他创作
大纲/内容
Spring,Spring MVC,Spring Boot 之间什么关系
Spring 包含了多个功能模块,其中最重要的是 Spring-Core(主要提供 IoC 依赖注入功能的支持) 模块, Spring 中的其他模块(比如 Spring MVC)的功能实现基本都需要依赖于该模块
Spring MVC 是 Spring 中的一个很重要的模块,主要赋予 Spring 快速构建 MVC 架构的 Web 程序的能力。MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码
Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,真正做到开箱即用,并且内置tomocat
springIoc
控制
指的是对象创建(实例化、管理)的权力
反转
控制权交给外部环境(Spring 框架、IoC 容器)
springBean
概念
Bean 代指的就是那些被 IoC 容器所管理的对象
申明bean的注解
@Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层
@Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面
@Component和@Bean区别
@Component 注解作用于类,而@Bean注解作用于方法
@Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中,@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我
@Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean
注入bean的注解
@Autowired
Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean
当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件
的选择,默认情况下它自己不知道选择哪一个,这种情况下,注入方式会变为 byName
当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件
的选择,默认情况下它自己不知道选择哪一个,这种情况下,注入方式会变为 byName
@Resource
@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType
如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType
如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType
@Inject
不常用
注入bean的方式
构造函数注入:通过类的构造函数来注入依赖项
Setter 注入:通过类的 Setter 方法来注入依赖项
Field(字段) 注入:直接在类的字段上使用注解(如 @Autowired 或 @Resource)来注入依赖项
官方推荐构造函数注入
1.依赖完整性:确保所有必需依赖在对象创建时就被注入,避免了空指针异常的风险。
2.不可变性:有助于创建不可变对象,提高了线程安全性。
3.初始化保证:组件在使用前已完全初始化,减少了潜在的错误。
4.测试便利性:在单元测试中,可以直接通过构造函数传入模拟的依赖项,而不必依赖 Spring 容器进行注入
2.不可变性:有助于创建不可变对象,提高了线程安全性。
3.初始化保证:组件在使用前已完全初始化,减少了潜在的错误。
4.测试便利性:在单元测试中,可以直接通过构造函数传入模拟的依赖项,而不必依赖 Spring 容器进行注入
Bean 的作用域
singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用
prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例
request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效
session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效
application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效
bean 是线程安全的吗
bean的生命周期
1.整体上可以简单分为四步:实例化 —> 属性赋值 —> 初始化 —> 销毁。
2.初始化这一步涉及到的步骤比较多,包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作。
3.销毁这一步会注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁
2.初始化这一步涉及到的步骤比较多,包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作。
3.销毁这一步会注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁
springAop
springAop的理解
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性
如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,,会使用 Cglib 生成一个被代理对象的子类来作为代理
aop术语
aop通知类型
Before(前置通知):目标对象的方法调用之前触发
After (后置通知):目标对象的方法调用之后触发
AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法
多个切面顺序如何控制
通常使用@Order 注解直接定义切面顺序,,@Order(3),值越小,优先级越高
切面、实现Ordered 接口重写 getOrder 方法
springMvc
核心组件
DispatcherServlet:核心的中央处理器,负责接收请求、分发,并给予客户端响应。
HandlerMapping:处理器映射器,根据 URL 去匹配查找能处理的 Handler ,并会将请求涉及到的拦截器和 Handler 一起封装
HandlerAdapter:处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的 Handler
Handler:请求处理器,处理实际请求的处理器
ViewResolver:视图解析器,根据 Handler 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 DispatcherServlet 响应客户端
工作原理
统一异常处理
推荐使用注解的方式统一异常处理,具体会使用到 @ControllerAdvice + @ExceptionHandler 这两个注解
spring框架用到的设计模式
工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象
代理设计模式 : Spring AOP 功能的实现
单例设计模式 : Spring 中的 Bean 默认都是单例的
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用
适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller
spring循环依赖
循环依赖是指 Bean 对象循环引用,是两个或多个 Bean 之间相互持有对方的引用,例如 CircularDependencyA → CircularDependencyB → CircularDependencyA
解决方式:三级缓存
一级缓存(singletonObjects):存放最终形态的 Bean(已经实例化、属性填充、初始化),单例池,为“Spring 的单例属性”⽽⽣。一般情况我们获取 Bean 都是从这里获取的,但是并不是所有的 Bean 都在单例池里面,例如原型 Bean 就不在里面
二级缓存(earlySingletonObjects):存放过渡 Bean(半成品,尚未属性填充),也就是三级缓存中ObjectFactory产生的对象,与三级缓存配合使用的,可以防止 AOP 的情况下,每次调用ObjectFactory#getObject()都是会产生新的代理对象的。
三级缓存(singletonFactories):存放ObjectFactory,ObjectFactory的getObject()方法(最终调用的是getEarlyBeanReference()方法)可以生成原始 Bean 对象或者代理对象(如果 Bean 被 AOP 切面代理)。三级缓存只会对单例 Bean 生效
具体流程
当 Spring 创建 A 之后,发现 A 依赖了 B ,又去创建 B,B 依赖了 A ,又去创建 A;在 B 创建 A 的时候,那么此时 A 就发生了循环依赖,由于 A 此时还没有初始化完成,因此在 一二级缓存 中肯定没有 A;那么此时就去三级缓存中调用 getObject() 方法去获取 A 的 前期暴露的对象 ,也就是调用上边加入的 getEarlyBeanReference() 方法,生成一个 A 的 前期暴露对象;然后就将这个 ObjectFactory 从三级缓存中移除,并且将前期暴露对象放入到二级缓存中,那么 B 就将这个前期暴露对象注入到依赖,来支持循环依赖
只涉及两级缓存够吗?
没有 AOP 的情况下,确实可以只使用一级和三级缓存来解决循环依赖问题。但是,当涉及到 AOP 时,二级缓存就显得非常重要了,因为它确保了即使在 Bean 的创建过程中有多次对早期引用的请求,也始终只返回同一个代理对象,从而避免了同一个 Bean 有多个代理对象的问题
三级缓存解决循环依赖的缺点
比如增加了内存开销(需要维护三级缓存,也就是三个 Map),降低了性能(需要进行多次检查和转换)。并且,还有少部分情况是不支持循环依赖的,比如非单例的 bean 和@Async注解的 bean 无法支持循环依赖
@Lazy懒加载解决循环依赖
1.没有 @Lazy 的情况下:在 Spring 容器初始化 A 时会立即尝试创建 B,而在创建 B 的过程中又会尝试创建 A,最终导致循环依赖(即无限递归,最终抛出异常)。
2.使用 @Lazy 的情况下:Spring 不会立即创建 B,而是会注入一个 B 的代理对象。由于此时 B 仍未被真正初始化,A 的初始化可以顺利完成。等到 A 实例实际调用 B 的方法时,代理对象才会触发 B 的真正初始化
2.使用 @Lazy 的情况下:Spring 不会立即创建 B,而是会注入一个 B 的代理对象。由于此时 B 仍未被真正初始化,A 的初始化可以顺利完成。等到 A 实例实际调用 B 的方法时,代理对象才会触发 B 的真正初始化
Spring事务
Spring 支持两种方式的事务管理
编程式事务管理
通过 TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助
声明式事务管理
推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)
Spring事务管理接口
PlatformTransactionManager:(平台)事务管理器,Spring 事务策略的核心。TransactionDefinition:事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。TransactionStatus:事务运行状态。
Spring 事务中哪几种事务传播行为?
TransactionDefinition.PROPAGATION_REQUIRED
使用的最多的一个事务传播行为,我们平时经常使用的@Transactional注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
TransactionDefinition.PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰
TransactionDefinition.PROPAGATION_NESTED
如果当前存在事务,就在嵌套事务内执行;如果当前没有事务,就执行与TransactionDefinition.PROPAGATION_REQUIRED类似的操作。
在外部方法开启事务的情况下,在内部开启一个新的事务,作为嵌套事务存在。
如果外部方法无事务,则单独开启一个事务,与 PROPAGATION_REQUIRED 类似
在外部方法开启事务的情况下,在内部开启一个新的事务,作为嵌套事务存在。
如果外部方法无事务,则单独开启一个事务,与 PROPAGATION_REQUIRED 类似
TransactionDefinition.PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常
Spring事务隔离级别
TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别
TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别
@Transactional(rollbackFor = Exception.class)注解
@Transactional 注解默认回滚策略是只有在遇到RuntimeException(运行时异常) 或者 Error 时才会回滚事务,而不会回滚 Checked Exception(受检查异常)
如果想要修改默认的回滚策略,可以使用 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性来指定哪些异常需要回滚,哪些异常不需要回滚
如果想要修改默认的回滚策略,可以使用 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性来指定哪些异常需要回滚,哪些异常不需要回滚
Spring Security
控制请求权限的方法
1.permitAll():无条件允许任何形式访问,不管你登录还是没有登录。
2.anonymous():允许匿名访问,也就是没有登录才可以访问。
3.denyAll():无条件决绝任何形式的访问。
3.authenticated():只允许已认证的用户访问。
4.fullyAuthenticated():只允许已经登录或者通过 remember-me 登录的用户访问。
5.hasRole(String) : 只允许指定的角色访问。
6.hasAnyRole(String) : 指定一个或者多个角色,满足其一的用户即可访问。
7.hasAuthority(String):只允许具有指定权限的用户访问
8.hasAnyAuthority(String):指定一个或者多个权限,满足其一的用户即可访问。
9.hasIpAddress(String) : 只允许指定 ip 的用户访问。
2.anonymous():允许匿名访问,也就是没有登录才可以访问。
3.denyAll():无条件决绝任何形式的访问。
3.authenticated():只允许已认证的用户访问。
4.fullyAuthenticated():只允许已经登录或者通过 remember-me 登录的用户访问。
5.hasRole(String) : 只允许指定的角色访问。
6.hasAnyRole(String) : 指定一个或者多个角色,满足其一的用户即可访问。
7.hasAuthority(String):只允许具有指定权限的用户访问
8.hasAnyAuthority(String):指定一个或者多个权限,满足其一的用户即可访问。
9.hasIpAddress(String) : 只允许指定 ip 的用户访问。
spring&springBoot常用注解
@SpringBootApplication
@SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合
@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
@ComponentScan:扫描被@Component (@Repository,@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
@Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
@ComponentScan:扫描被@Component (@Repository,@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
@Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
@Autowired
自动导入对象到类中,被注入进的类同样要被 Spring 容器管理比如:Service 类注入到 Controller 类中
@Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层
@Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面
@RestController:注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直接填入 HTTP 响应体中,是 REST 风格的控制器
@Scope:声明 Spring Bean 的作用域
@Configuration:一般用来声明配置类,可以使用 @Component注解替代,不过使用@Configuration注解声明配置类更加语义化
@RequestBody:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去
读取配置信息注解
@Value("${property}") 读取比较简单的配置信息
@ConfigurationProperties读取配置信息并与 bean 绑定
@PropertySource读取指定 properties 文件
参数校验注解
验证请求参数
全局处理controller异常
@ControllerAdvice :注解定义全局异常处理类
@ExceptionHandler :注解声明异常处理方法
@ExceptionHandler :注解声明异常处理方法
Json数据处理
@JsonIgnoreProperties 作用在类上用于过滤掉特定字段不返回或者不解析。
@JsonIgnore一般用于类的属性上,作用和上面的@JsonIgnoreProperties 一样。
@JsonFormat一般用来格式化 json 数据
@JsonUnwrapped:扁平化对象
springBoot自动装配
什么是spring自动装配
没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可,简单理解为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能
如何实现
EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector
第一步
第二步
第三步
第四步
0 条评论
下一页