SpringBoot面试总结
其实就是对以前文章的一个总结,单独再写一篇文章的原因是,自己对某些知识点有了一些理解,但最重要的一点是AI总结的比自己整理的简直是好太多了。
IOC
IoC(控制反转) 是一种设计思想:将对象的创建、组装和依赖关系的管理权,从代码中反转给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的作用域(常用两个)

AOP
AOP(面向切面编程) 是一种编程范式,它允许你将那些横切关注点(如日志、事务、权限校验)从业务逻辑中抽离出来,形成独立的模块(称为切面),在运行时通过动态代理机制织入到目标方法中。


“AOP的核心思想是将横切关注点从业务代码中分离,通过动态代理在运行时织入。在Spring中,我主要用到 @Aspect 定义切面,用 @Pointcut 定义切入点表达式,用5种通知(@Before、@After、@Around等)在目标方法的不同时机执行横切逻辑。底层实现是JDK动态代理或CGLIB代理,由Spring容器在Bean初始化时自动生成代理对象。我们项目里主要用于统一日志记录、接口耗时监控和权限校验,减少重复代码,提升维护性。”
package com.example.springbootstudy.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* 使用AOP切Controller打印日志
*
* @author 阿无
* @version 1.0.0
* @since 2024/8/19 - 10:57
*/
@Aspect
@Component
public class LogAspect {
private static Log logger = LogFactory.getLog(LogAspect.class);
// 记录保存所有controller层的日志
@Pointcut("execution(public * com.example.springbootstudy.controller..*.*(..))")
public void pointCutControllerLog(){
}
@Around("pointCutControllerLog()")
public Object controllerLog(ProceedingJoinPoint point) throws Throwable{
return logCommon(point,null);
}
// 如果非Controller层也需要保存日志,则可以使用注解的形式
// 另一种写法是
// @Around("@annotation(com.example.springbootstudy.aop.SysLogAnno)")
@Around("@annotation(sysLogAnno)")
public Object sysLog(ProceedingJoinPoint point,SysLogAnno sysLogAnno) throws Throwable{
return logCommon(point,sysLogAnno);
}
public Object logCommon(ProceedingJoinPoint point,SysLogAnno sysLogAnno) throws Throwable{
Long startTime = System.currentTimeMillis();
LocalDateTime localDateTimeStart = LocalDateTime.now();
String className = point.getTarget().getClass().getName();
String message = sysLogAnno!=null ? sysLogAnno.value():null;
String methodName = point.getSignature().getName();
Object[] args = point.getArgs();
// 参数全部转换为字符串并以,分割 否则就是一个空字符串
String argsString = args!=null ? Arrays.stream(args).map(Object::toString)
.collect(Collectors.joining(",")) : "";
// 1. 获取request对象
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 1.1 请求方式
String requestMethod = request.getMethod();
// 1.2 请求地址/路径
String requestURI = request.getRequestURI();
// 1.3 访问来源ip
String remoteAddr = request.getRemoteAddr();
// 1.4 还可以获取用户登录的信息 我们在这儿暂时不需要
// 可以把Object强转成User类
// Object user_var = request.getSession().getAttribute("user_var");
SysLog sysLog = new SysLog(className,methodName, message, argsString, null,
null, localDateTimeStart,null,null,requestMethod,requestURI,remoteAddr);
Object result = point.proceed();
Long endTime = System.currentTimeMillis();
LocalDateTime localDateTimeEnd = LocalDateTime.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(className=com.example.springbootstudy.service.LogTestService, methodName=testLog, message=LogTestService,
// args=1,jay, result=1 jay, status=success, localDateTimeStart=2024-08-19T19:57:03.552, localDateTimeEnd=2024-08-19T19:57:03.555,
// totalTime=3, requestMethod=GET, requestURI=/testAnnoLog/1, remoteAddr=127.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(className=com.example.springbootstudy.controller.LogTestController, methodName=testAnnoLog, message=null,
// args=1,jay, result=1 jay, status=success, localDateTimeStart=2024-08-19T19:57:03.502, localDateTimeEnd=2024-08-19T19:57:03.555,
// totalTime=56, requestMethod=GET, requestURI=/testAnnoLog/1, remoteAddr=127.0.0.1)
// 这里的结果就是拦截的方法的结果
return result;
}
}
配置文件的优先级
优先级结论:bootstrap.yml / bootstrap.properties > application.yml ≈ application.properties(两者同级,避免混用)。
实际项目建议:
使用 bootstrap.yml:仅在需要接入Spring Cloud Config或配置中心时使用,且只放引导配置。
使用 application.yml:作为日常开发的主要配置文件,因为它结构清晰,支持层级关系。
避免使用 application.properties:除非是遗留项目,否则优先选择application.yml,保持配置方式统一。
一句话总结
bootstrap.yml 先加载,用于引导系统;application.yml 后加载,用于定义业务。同名的 application.properties 与 application.yml 不建议同时使用。
更多推荐


所有评论(0)