🍅 作者简介:王哥,CSDN2022博客总榜Top100🏆、博客专家💪
🍅 技术交流:定期更新Java硬核干货,不定期送书活动
🍅 王哥多年工作总结:Java学习路线总结, 点击 突击面试
🍅 数十万人的面试选择: 面试说人话系列《面试1v1》
我是 javapub,一名 Markdown
程序员从👨💻,八股文种子选手。
《面试1v1》 连载中…
我是 javapub,一名 Markdown
程序员从👨💻,八股文种子选手。
面试官: 想请你简单介绍一下 Spring 框架,它的核心特性是什么?
候选人: Spring 是一个开源框架,目的是简化 JavaEE 开发。它的核心特性有:
- IoC(Inverse of Control):通过 DI(Dependency Injection)实现将对象间的依赖关系交给 Spring 管理。
- AOP(Aspect Oriented Programming):面向切面编程,可以在程序运行期间动态的将某段代码切入到指定的方法、指定的位置进行运行。
- Portlet MVC:Spring 提供 MVC 框架可以快速开发 Web 应用。
- 事务管理:Spring 提供广泛的事务管理接口,支持 JDBC、Hibernate 等事务管理。
- Spring 统一一体化了其他框架和技术,如:Struts、Hibernate、Quartz 等。
面试官(笑):你说的真是五花八门,让我有点晕,来聊点具体的吧。Spring 是如何工作的,它如何用于构建 Web 应用程序?
候选人: 好的,Spring 的工作原理主要是 IoC 容器。对 Web 应用来说,Spring MVC 是基于 JavaEE 的 Model-View-Controller 设计模式构建的,主要工作流程是:
- 浏览器发送请求到 DispatcherServlet。
- DispatcherServlet 接收请求后会转交给 HandlerMapping 得到请求对应的 Handler。
- HandlerMapping 将 Handler 映射到 HandlerAdapter。
- HandlerAdapter 调用 Handler 处理请求,Handler 会返回一个 ModelAndView。
- ViewResolver 解析 ModelAndView,找到正确的 View。
- DispatcherServlet 将 View 返回给浏览器。
通过这个流程,Spring MVC 应用了 MVC 模式,实现了业务逻辑、控制逻辑、表现逻辑的分离,使我们可以更加专注于业务开发。
面试官: 你说的很具体,我明白了。那么 Spring 可以在哪些实际场景中使用?开发人员在使用 Spring 时常犯哪些错误?
候选人: Spring 可以应用在很多实际场景中:
- Web 应用:Spring MVC 是 Spring 体系中最为成熟的框架,可以用来开发网站、BBS、博客等 Web 应用。
- 企业应用:Spring 提供事务管理、数据访问等功能,非常适用于开发企业级应用。
- 微服务:Spring Boot 提供了快速开发单个微服务的能力,配合 Spring Cloud 可以开发微服务架构的系统。
- Android 应用:Spring for Android 提供了在 Android 应用中使用 Spring 的能力。
开发人员在使用 Spring 时常犯的几个错误:
- 容器管理对象依赖关系错乱:未正确配置 bean 的依赖关系,导致依赖注入错误。
- 上下文目录 problemas:beans.xml 配置文件放在了非上下文目录,导致 Spring 无法识别。
- 事务管理错误:未正确配置事务属性,导致事务管理不生效。
- AOP 误用:滥用 AOP 或错误使用 AOP 导致 sistem 过于复杂或 AOP 不生效。
- 未考虑扩展性:在开发初期未考虑系统扩展性,导致系统难以演进。
面试官: 那么如何使基于 Spring 的应用程序更高效、更可扩展?
候选人: 这里有几点建议:
- 采用模块化设计,遵循高内聚低耦合原则,每个模块保持高内聚,模块之间低耦合。
- 使用设计模式,如工厂模式、单例模式、代理模式等,提高系统扩展性。
- 应用 AOP,通过预置切点在不修改源代码的情况下增加新功能。
- 使用 Spring 的事件机制,通过事件监听器监听事件,当事件触发时执行相应逻辑。
- 应用 Spring 的 Profile 功能,可以根据环境部署不同的 bean,提高系统灵活性。
- 使用 Spring Boot 依赖管理和自动配置的能力,简化构建过程,提高开发效率。
- 应用微服务架构,将单体应用拆分成职责单一、松耦合的服务,更容易扩展和升级。
- 使用缓存技术,如 Redis 缓存数据库查询结果,降低数据库压力,提高系统吞吐量。
面试官: 很棒,你对 Spring 和高可扩展系统的理解很透彻!最后一个问题,Spring 的源码中 IoC 容器的实现你可以大致描述一下吗?
候选人: 可以的,IoC 容器的实现主要在 AbstractApplicationContext 及其子类 ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext 中。主要流程是:
- 容器启动时会调用 refresh() 方法,其中会调用 obtainFreshBeanFactory() 方法初始化 DefaultListableBeanFactory,此为 IoC 容器的核心。
// AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
// 初始化 BeanFactory
DefaultListableBeanFactory beanFactory = obtainFreshBeanFactory();
}
- 然后会调用 loadBeanDefinitions(beanFactory) 方法加载 bean 定义,主要通过 XmlBeanDefinitionReader 解析 bean 定义文件。
// AbstractXmlApplicationContext.java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
- bean 实例化阶段会调用 getBean() 方法,通过工厂方法或构造器实例化 bean。
- 实例化 bean 后,会对 bean 进行属性注入、初始化以及其他Aware接口回调。
- bean 的生命周期至此结束,容器会对 bean 进行管理,直至容器关闭。
这就是 IoC 容器实现的大致流程,关键是 bean 定义资源的加载和解析,以及 bean 的实例化及生命周期管理。IoC 容器屏蔽了 bean 之间的依赖关系,使 bean 的使用者可以零配置使用 bean。
面试官: 你的解释很到位,IoC 容器的源码分析确实需要对它的原理有深入了解。最后一个问题,在你的项目中是如何设计一个高并发的系统的?
候选人: 设计一个高并发系统,有以下几点建议:
- 选择高性能技术栈:选择支持高并发的语言(Java、Go 等)和框架(Spring、Vert.x 等)。
- 采用分布式和微服务架构:将系统拆分为多个单一职责的服务,部署在不同服务器上,可以实现高可用和负载均衡。
- 选择高性能存储:使用能支撑高并发读写的数据库,如 Redis、Kafka 等。对关系型数据库进行分库分表、添加缓存等优化。
- 限流与降级:使用限流手段控制流量,避免被高流量打垮;使用降级策略保证核心服务可用。
- 缓存与异步:对频繁读取数据的接口使用缓存;对非关键性计算使用异步处理,避免线程阻塞。
- 服务治理:使用服务注册与发现、熔断器、网关等手段管理各服务。
- 线程模型优化:根据业务选择恰当的线程模型。如对大量短连接使用线程池;对长连接使用主从 Reactor 线程模型等。
- 利用好硬件资源:合理分配 CPU 和内存资源给应用;利用好多核 CPU 进行并行计算等。
- 测试与监控:进行压力测试,监控系统的负载、吞吐量和延迟指标,并进行优化。
- 容错和自动恢复:设计稳定的容错方案,当系统发生故障时可以自动检测并恢复。
这些方面搭配得当,可以设计一个高性能、高并发的系统。但需要权衡系统复杂性,在满足需求前提下保持最简实现。
面试官: 很棒,你在高并发系统设计方面有很强的理解力和丰富经验。
最近我在更新《面试1v1》系列文章,主要以场景化的方式,讲解我们在面试中遇到的问题,致力于让每一位工程师拿到自己心仪的offer,感兴趣可以关注JavaPub追更!
《面试1v1》 连载中…
🎁目录合集:
Gitee:https://gitee.com/rodert/JavaPub
GitHub:https://github.com/Rodert/JavaPub
http://javapub.net.cn