SSM拷打第二讲!!!

7. Spring中的循环引用?

复制代码
是什么->能解决的是什么->三级缓存

Spring 的循环依赖就是 Bean 之间互相依赖,比如 A 依赖 B,B 又依赖 A。

Spring 能解决的主要是单例 Bean 的属性注入循环依赖。它的核心思路是:A 实例化之后,还没完成属性填充和初始化,就先把 A 的早期引用暴露出来;这时 B 创建时需要 A,就可以先拿到这个早期引用,等 B 创建完再回头完成 A 的注入。

三级缓存里,一级缓存放完整 Bean,二级缓存放早期 Bean,三级缓存放 ObjectFactory。三级缓存的意义主要是为了在有 AOP 的情况下,能提前拿到代理对象,避免注入原始对象。

但构造器循环依赖和原型 Bean 循环依赖解决不了,因为它们没法像单例属性注入那样提前暴露引用。

8. 那具体解决流程清楚吗?

Spring 解决单例属性注入循环依赖,大概流程可以用 A、B 互相依赖来理解。

创建 A 的时候,Spring 会先把 A 实例化出来,但这时 A 还没有完成属性注入和初始化。为了避免后面别人依赖 A 时拿不到对象,Spring 会把一个能获取 A 早期引用的 ObjectFactory 放到第三级缓存里。

接着 A 做属性填充,发现需要 B,就去创建 B。B 也会先实例化,并且提前暴露。然后 B 属性填充时发现需要 A,这时候 Spring 会从 A 的第三级缓存里拿到 ObjectFactory,通过它拿到 A 的早期引用,放到二级缓存,并注入给 B。

B 完成初始化后进入一级缓存。然后回到 A,A 就可以注入已经创建好的 B,最后 A 也完成初始化,进入一级缓存,同时清理之前的早期引用缓存。

这里要注意,ObjectFactory 不是重新创建 A,而是返回 A 的早期引用;如果 A 需要 AOP,它返回的可能就是代理对象。

9. 构造方法出现了循环依赖怎么解决?

构造器循环依赖 Spring 默认是解决不了的。比如 A 的构造方法需要 B,B 的构造方法又需要 A,这时候 A 和 B 都还没实例化完成,Spring 没有任何一个早期对象可以提前暴露,所以三级缓存也救不了。

解决上,我一般不会优先想着硬绕过去,而是先看是不是设计有问题,比如把互相依赖的逻辑抽到第三个服务里,或者重新拆分职责。如果只是技术上要临时打破这个循环,可以用 @Lazy,让其中一个依赖注入懒加载代理对象;也可以改成 Setter 或字段注入,让对象先实例化出来,再做属性填充。但从设计上看,构造器循环依赖通常是不太好的信号。

10. SpringMVC的执行流程?

SpringMVC = Java 后端接收请求、调用 Controller、返回响应的框架。

SpringMVC 的核心入口是 DispatcherServlet。请求进来后,先由 DispatcherServlet 接收,然后通过 HandlerMapping 找到对应的 Controller 方法,同时拿到相关拦截器。

接着 DispatcherServlet 会交给 HandlerAdapter 去真正调用 Controller。在这个过程中,SpringMVC 会完成参数解析、数据绑定、类型转换这些工作。Controller 执行完之后会返回结果。

如果是传统页面请求,返回的可能是 ModelAndView,然后通过 ViewResolver 解析视图,最后渲染页面返回给浏览器。

如果是现在常见的 REST 接口,比如 @RestController,一般不会走视图解析,而是通过 HttpMessageConverter 把返回对象转成 JSON,再写回响应体。

11. Springboot自动配置原理

Spring Boot 自动配置的入口一般是 @SpringBootApplication,它里面包含了 @EnableAutoConfiguration,这个是自动配置的核心。

@EnableAutoConfiguration 会通过 @Import 导入 AutoConfigurationImportSelector,然后去加载自动配置类清单。老版本主要是从 META-INF/spring.factories 里读,Spring Boot 3 之后主要是从 AutoConfiguration.imports 里读。

这些自动配置类不会无脑生效,而是会配合很多条件注解判断,比如 classpath 里有没有某个类、用户有没有自己定义 Bean、配置文件里有没有开启某个属性。只有条件满足时,Spring Boot 才会把对应的 Bean 注册到容器里。

12. Spring 的常见注解有哪些?

Spring 常见注解我一般按使用场景来分。

第一类是 Bean 注册,比如 @Component,以及它的语义化扩展 @Service@Repository@Controller

第二类是依赖注入,比如 @Autowired@Resource@Qualifier

第三类是配置相关,比如 @Configuration@Bean@ComponentScan

第四类是 Web 开发里常用的,比如 @RestController@RequestMapping@GetMapping@PostMapping@RequestBody@ResponseBody。还有事务相关的 @Transactional,AOP 相关的 @Aspect@Around@Pointcut

如果是 Spring Boot 项目,还会常用 @SpringBootApplication,它是启动类上的复合注解。

相关推荐
圆山猫5 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
城管不管5 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
IT小白杨5 小时前
从环境制备到自动化工作流:多账号运营的工程化架构拆解
java·经验分享·自动化·安全架构·指纹浏览器
豆瓣鸡6 小时前
算法日记 - Day3
java·开发语言·算法
萧瑟余晖6 小时前
Java深入解析篇九之NIO详解
java·网络·nio
The Chosen One9856 小时前
高进度算法模板速记(待完善)
java·前端·算法
极光代码工作室9 小时前
基于SpringBoot的课程预约系统
java·springboot·web开发·后端开发
Leighteen9 小时前
`try-finally` 里的 `return`:为什么 `finally` 会悄悄改掉返回值、吞掉异常
java·开发语言
名字还没想好☜10 小时前
Go 的 time.After 在 select 循环里内存泄漏:定时器堆积原理与 timer.Reset 正确姿势
java·数据库·golang·go·goroutine
圆山猫10 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v