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