SpringBoot面试总结

📅 2026/8/5 10:15:06
SpringBoot面试总结
其实就是对以前文章的一个总结单独再写一篇文章的原因是自己对某些知识点有了一些理解但最重要的一点是AI总结的比自己整理的简直是好太多了。IOCIoC控制反转是一种设计思想将对象的创建、组装和依赖关系的管理权从代码中反转给Spring容器。你的代码不再主动new对象而是由容器来创建并注入。IoC容器主要管理什么面试常问Bean的实例化容器负责创建对象默认是单例。Bean的依赖装配容器负责将Bean所依赖的其他Bean注入进去通过构造器、Setter或字段。Bean的生命周期管理容器负责管理Bean的初始化、销毁等生命周期回调。依赖注入的三种方式Resource和Autowired的区别都是用来自动装配的都可以放在属性字段上Autowired是spring声明的Resource是jdk声明的Autowired默认按照类型注入如果类型有多个则按照名称注入Resource默认按照名称注入如果没有该名称的对象则按照类型注入如果两个都找不到就报错这里的名称和类型实际上就是指该类的对象的名称和该类Spring如何实现IoC底层原理配置阶段通过 XML、注解或Java配置类定义Bean及其依赖关系。解析与注册Spring容器启动时读取配置解析为BeanDefinition对象并注册到容器中。实例化与装配根据BeanDefinition通过反射创建Bean实例并按照配置进行依赖注入构造器注入、Setter注入等。生命周期回调Bean创建完成后执行初始化方法如PostConstruct容器关闭时执行销毁方法。Bean的作用域常用两个AOPAOP面向切面编程是一种编程范式它允许你将那些横切关注点如日志、事务、权限校验从业务逻辑中抽离出来形成独立的模块称为切面在运行时通过动态代理机制织入到目标方法中。“AOP的核心思想是将横切关注点从业务代码中分离通过动态代理在运行时织入。在Spring中我主要用到 Aspect 定义切面用 Pointcut 定义切入点表达式用5种通知Before、After、Around等在目标方法的不同时机执行横切逻辑。底层实现是JDK动态代理或CGLIB代理由Spring容器在Bean初始化时自动生成代理对象。我们项目里主要用于统一日志记录、接口耗时监控和权限校验减少重复代码提升维护性。”packagecom.example.springbootstudy.aop;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Pointcut;importorg.springframework.stereotype.Component;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjavax.servlet.http.HttpServletRequest;importjava.time.LocalDateTime;importjava.util.Arrays;importjava.util.stream.Collectors;/** * 使用AOP切Controller打印日志 * * author 阿无 * version 1.0.0 * since 2024/8/19 - 10:57 */AspectComponentpublicclassLogAspect{privatestaticLogloggerLogFactory.getLog(LogAspect.class);// 记录保存所有controller层的日志Pointcut(execution(public * com.example.springbootstudy.controller..*.*(..)))publicvoidpointCutControllerLog(){}Around(pointCutControllerLog())publicObjectcontrollerLog(ProceedingJoinPointpoint)throwsThrowable{returnlogCommon(point,null);}// 如果非Controller层也需要保存日志则可以使用注解的形式// 另一种写法是// Around(annotation(com.example.springbootstudy.aop.SysLogAnno))Around(annotation(sysLogAnno))publicObjectsysLog(ProceedingJoinPointpoint,SysLogAnnosysLogAnno)throwsThrowable{returnlogCommon(point,sysLogAnno);}publicObjectlogCommon(ProceedingJoinPointpoint,SysLogAnnosysLogAnno)throwsThrowable{LongstartTimeSystem.currentTimeMillis();LocalDateTimelocalDateTimeStartLocalDateTime.now();StringclassNamepoint.getTarget().getClass().getName();StringmessagesysLogAnno!null?sysLogAnno.value():null;StringmethodNamepoint.getSignature().getName();Object[]argspoint.getArgs();// 参数全部转换为字符串并以分割 否则就是一个空字符串StringargsStringargs!null?Arrays.stream(args).map(Object::toString).collect(Collectors.joining(,)):;// 1. 获取request对象ServletRequestAttributesrequestAttributes(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequestrequestAttributes.getRequest();// 1.1 请求方式StringrequestMethodrequest.getMethod();// 1.2 请求地址/路径StringrequestURIrequest.getRequestURI();// 1.3 访问来源ipStringremoteAddrrequest.getRemoteAddr();// 1.4 还可以获取用户登录的信息 我们在这儿暂时不需要// 可以把Object强转成User类// Object user_var request.getSession().getAttribute(user_var);SysLogsysLognewSysLog(className,methodName,message,argsString,null,null,localDateTimeStart,null,null,requestMethod,requestURI,remoteAddr);Objectresultpoint.proceed();LongendTimeSystem.currentTimeMillis();LocalDateTimelocalDateTimeEndLocalDateTime.now();// 但凡执行到这儿的就是成功的异常往上抛就行交给全局异常处理器sysLog.setStatus(success);sysLog.setResult(result!null?result.toString():null);sysLog.setLocalDateTimeEnd(localDateTimeEnd);sysLog.setTotalTime(endTime-startTime);// 理论上这个日志应该是保存在es中的应该logger.info(日志记录正常);logger.info(sysLog);// 2024-08-19 19:57:03.555 INFO 19756 --- [nio-8080-exec-1] c.example.springbootstudy.aop.LogAspect :// SysLog(classNamecom.example.springbootstudy.service.LogTestService, methodNametestLog, messageLogTestService,// args1,jay, result1 jay, statussuccess, localDateTimeStart2024-08-19T19:57:03.552, localDateTimeEnd2024-08-19T19:57:03.555,// totalTime3, requestMethodGET, requestURI/testAnnoLog/1, remoteAddr127.0.0.1)// 2024-08-19 19:57:03.555 INFO 19756 --- [nio-8080-exec-1] c.example.springbootstudy.aop.LogAspect : 日志记录正常// 2024-08-19 19:57:03.555 INFO 19756 --- [nio-8080-exec-1] c.example.springbootstudy.aop.LogAspect :// SysLog(classNamecom.example.springbootstudy.controller.LogTestController, methodNametestAnnoLog, messagenull,// args1,jay, result1 jay, statussuccess, localDateTimeStart2024-08-19T19:57:03.502, localDateTimeEnd2024-08-19T19:57:03.555,// totalTime56, requestMethodGET, requestURI/testAnnoLog/1, remoteAddr127.0.0.1)// 这里的结果就是拦截的方法的结果returnresult;}}配置文件的优先级SpringBoot中的设计模式“我在项目里经常用到或接触到Spring框架中的几种设计模式比如工厂模式、模板方法模式、代理模式、策略模式、观察者模式和单例模式。工厂模式就像一个大管家帮我们创建和管理对象模板方法模式把固定流程封装好把变化的步骤留给我们定制代理模式是Spring AOP的底层支撑实现无侵入式的功能增强策略模式让算法可以灵活切换观察者模式通过事件驱动实现组件解耦而单例模式保证了Bean在容器中唯一实例。工厂模式 —— Bean的“总管家”BeanFactory和ApplicationContext是工厂模式的核心体现。我们通过Autowired或Resource获取Bean无需关心对象是如何实例化、如何组装依赖的这些全由Spring容器这个“大工厂”帮我们完成。模板方法模式 —— 固定流程“骨架”最典型的是JdbcTemplate。它定义了SQL执行的标准流程获取连接、执行语句、处理结果集、关闭连接但具体的SQL语句和结果集映射逻辑由我们通过回调接口传入。这样既复用了代码又把变化的部分留给我们自定义。代理模式 —— AOP的“幕后功臣”Spring AOP的底层就是动态代理。比如在方法上加TransactionalSpring会在运行时为目标对象生成代理在代理中开启事务、执行方法、提交/回滚实现无侵入式增强。JDK动态代理基于接口CGLIB基于子类Spring会根据目标类自动选择。策略模式 —— 算法的“多选一”最经典的例子是事务管理。PlatformTransactionManager接口有多个实现DataSourceTransactionManagerJDBC/MyBatis、JpaTransactionManagerJPA等。Spring运行时根据配置动态选择合适的策略我们只需要切换配置上层代码完全无感知。观察者模式 —— 启动流程的“广播系统”Spring Boot启动过程中发布了十几种事件如ApplicationStartingEvent、ApplicationReadyEvent各种ApplicationListener监听并响应。这正是观察者模式的应用。我可以通过自定义监听器在应用启动后执行初始化操作例如缓存预热。单例模式 —— Bean的“默认作用域”Spring中Bean默认是单例的由容器保证每个BeanDefinition只创建一个实例所有依赖方共享同一个对象。这减少了对象创建开销适合无状态的Service、DAO。与传统单例不同Spring是“容器级单例”通过Scope(“prototype”)可随时改为多例业务代码零改动。SpringBoot中的实现模板模式// 模板类// RestTemplate.javapublicTTgetForObject(Stringurl,ClassTresponseType){// 模板方法入口调用 execute 方法returnexecute(url,HttpMethod.GET,null,newHttpMessageConverterExtractorT(responseType,getMessageConverters()));}// RestTemplate.javapublicTTexecute(Stringurl,HttpMethodmethod,RequestCallbackrequestCallback,ResponseExtractorTresponseExtractor){// 1. 创建请求对象固定ClientHttpRequestrequestcreateRequest(url,method);// 2. 执行回调让调用者自定义请求体变化的部分if(requestCallback!null){requestCallback.doWithRequest(request);}// 3. 执行请求获取响应固定ClientHttpResponseresponserequest.execute();// 4. 处理响应状态固定handleResponse(url,method,response);// 5. 提取响应体转为目标对象变化的部分通过 ResponseExtractor 回调returnresponseExtractor.extractData(response);}// 回调接口变化的部分// 请求回调让你自定义请求头、请求体FunctionalInterfacepublicinterfaceRequestCallback{voiddoWithRequest(ClientHttpRequestrequest)throwsIOException;}// 响应提取器让你自定义如何把响应转成对象FunctionalInterfacepublicinterfaceResponseExtractorT{TextractData(ClientHttpResponseresponse)throwsIOException;}// 测试UseruserrestTemplate.getForObject(http://api.com/user/1,User.class);项目中的使用策略模式订单创建设计意图将订单创建的复杂逻辑根据订单类型进行拆分每种订单类型有独立的实现类便于维护和扩展。正常优惠券订单详情创建捆绑商品订单详情创建预售订单详情创建订单改价策略正常订单改价预售订单改价保卡订单改价工厂模式