Spring 面试题
目录
- Spring 核心概念
- Spring IoC 容器
- Spring AOP
- Spring Bean 生命周期
- Spring 事务管理
- SpringMVC
- SpringBoot
- Spring 性能优化
- Spring 安全
- 实际应用场景
Spring 核心概念
1. 什么是 Spring 框架?它的核心特性是什么?
答案: Spring 是一个轻量级的、开源的 Java 企业级应用开发框架,由 Rod Johnson 在 2003 年创建。
核心特性:
- IoC(控制反转):将对象的创建和依赖关系的管理交给 Spring 容器
- AOP(面向切面编程):将横切关注点从业务逻辑中分离出来
- 依赖注入(DI):通过配置文件或注解自动注入依赖对象
- 声明式事务管理:通过注解或 XML 配置管理事务
- 模块化设计:各个模块可以独立使用
实际应用场景:
// 传统方式
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 硬编码依赖
public User getUser(Long id) {
return userDao.findById(id);
}
}
// Spring方式
@Service
public class UserService {
@Autowired
private UserDao userDao; // Spring自动注入依赖
public User getUser(Long id) {
return userDao.findById(id);
}
}
2. Spring 框架的模块架构是怎样的?
答案: Spring 框架采用分层架构,主要包含以下模块:
核心容器层(Core Container):
spring-core:核心工具类spring-beans:Bean 工厂和 Bean 的装配机制spring-context:构建于 core 和 beans 模块之上,提供框架式的对象访问方式spring-expression:Spring 表达式语言
数据访问层(Data Access/Integration):
spring-jdbc:JDBC 抽象层spring-orm:对象关系映射集成spring-oxm:对象 XML 映射spring-jms:Java 消息服务
Web 层:
spring-web:基本的 Web 开发功能spring-webmvc:MVC 框架spring-websocket:WebSocket 支持
AOP 层:
spring-aop:面向切面编程spring-aspects:AspectJ 集成
测试层:
spring-test:单元测试和集成测试支持
Spring IoC 容器
3. 什么是 IoC?它的工作原理是什么?
答案: IoC(Inversion of Control,控制反转)是一种设计模式,它将原本在程序中手动创建对象的控制权交给 Spring 框架来管理。
工作原理:
- 配置元数据:通过 XML、注解或 Java 代码配置 Bean 的定义
- Bean 工厂:Spring 容器读取配置元数据
- 依赖解析:解析 Bean 之间的依赖关系
- 对象创建:创建 Bean 实例并注入依赖
- 生命周期管理:管理 Bean 的创建、使用和销毁
代码示例:
// 配置类
@Configuration
public class AppConfig {
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean
public UserService userService() {
return new UserService(userDao()); // 依赖注入
}
}
// 使用
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
4. Spring IoC 容器有哪些?它们有什么区别?
答案: Spring 提供了两种主要的 IoC 容器:
1. BeanFactory(基础容器):
- 最基本的容器,提供基本的 IoC 功能
- 延迟加载 Bean,只有在 getBean()时才创建
- 功能相对简单,适合资源受限的环境
2. ApplicationContext(高级容器):
- 继承自 BeanFactory,提供更多企业级功能
- 预加载所有单例 Bean
- 支持国际化、事件发布、资源访问等
具体实现类:
// BeanFactory实现
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
// ApplicationContext实现
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
ApplicationContext context2 = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext context3 = new FileSystemXmlApplicationContext("file:beans.xml");
区别对比:
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| Bean 实例化 | 延迟加载 | 预加载 |
| 国际化支持 | 否 | 是 |
| 事件发布 | 否 | 是 |
| 资源访问 | 基础 | 增强 |
| 性能 | 更快启动 | 更快运行 |
5. Spring Bean 的作用域有哪些?
答案: Spring Bean 支持以下作用域:
1. singleton(单例,默认):
- 整个 Spring 容器中只有一个 Bean 实例
- 所有对该 Bean 的引用都指向同一个实例
- 适合无状态的 Bean
2. prototype(原型):
- 每次请求都创建一个新的 Bean 实例
- 适合有状态的 Bean
3. request(请求):
- 每个 HTTP 请求创建一个新的 Bean 实例
- 仅在 Web 应用中有效
4. session(会话):
- 每个 HTTP 会话创建一个新的 Bean 实例
- 仅在 Web 应用中有效
5. application(应用):
- 整个 Web 应用创建一个 Bean 实例
- 仅在 Web 应用中有效
6. websocket:
- 每个 WebSocket 会话创建一个 Bean 实例
代码示例:
@Component
@Scope("singleton") // 默认,可省略
public class SingletonBean {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
@Component
@Scope("prototype")
public class PrototypeBean {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
// 测试
@Autowired
private SingletonBean singletonBean1;
@Autowired
private SingletonBean singletonBean2;
@Autowired
private PrototypeBean prototypeBean1;
@Autowired
private PrototypeBean prototypeBean2;
// singletonBean1 == singletonBean2 (true)
// prototypeBean1 == prototypeBean2 (false)
Spring AOP
6. 什么是 AOP?Spring AOP 的实现原理是什么?
答案: AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,用于将横切关注点(如日志、事务、安全等)从业务逻辑中分离出来。
Spring AOP 实现原理: Spring AOP 使用代理模式实现,主要有两种代理方式:
1. JDK 动态代理(默认):
- 基于接口的代理
- 使用
Proxy.newProxyInstance()创建代理对象 - 目标类必须实现接口
2. CGLIB 代理:
- 基于继承的代理
- 通过继承目标类创建子类
- 可以代理没有实现接口的类
代码示例:
// 切面
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Before method: " + methodName);
}
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("After method: " + methodName);
}
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("Method execution time: " + (end - start) + "ms");
return result;
}
}
// 目标类
@Service
public class UserService {
public User getUser(Long id) {
// 业务逻辑
return new User(id, "张三");
}
}
7. Spring AOP 中的切点表达式有哪些?
答案: Spring AOP 支持多种切点表达式:
1. 方法执行切点:
// 匹配所有public方法
@Pointcut("execution(public * *(..))")
// 匹配com.example包下所有类的所有方法
@Pointcut("execution(* com.example.*.*(..))")
// 匹配UserService类的所有方法
@Pointcut("execution(* com.example.service.UserService.*(..))")
// 匹配以get开头的方法
@Pointcut("execution(* get*(..))")
// 匹配特定参数类型的方法
@Pointcut("execution(* *(Long, String))")
2. 方法签名切点:
// 匹配特定注解的方法
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
// 匹配特定注解的类
@Pointcut("@within(org.springframework.stereotype.Service)")
// 匹配特定注解的参数
@Pointcut("@args(org.springframework.validation.annotation.Valid)")
3. 组合切点:
// 组合多个切点
@Pointcut("execution(* com.example.service.*.*(..)) && args(id)")
public void serviceMethodWithId(Long id) {}
// 使用组合切点
@Before("serviceMethodWithId(id)")
public void logServiceMethod(Long id) {
System.out.println("Service method called with id: " + id);
}
Spring Bean 生命周期
8. Spring Bean 的生命周期是怎样的?
答案: Spring Bean 的生命周期包含以下阶段:
1. 实例化阶段:
- 容器创建 Bean 实例
2. 属性设置阶段:
- 设置 Bean 的属性值
- 注入依赖
3. 初始化阶段:
- 调用 BeanNameAware 接口方法
- 调用 BeanFactoryAware 接口方法
- 调用 ApplicationContextAware 接口方法
- 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
- 调用 InitializingBean 接口的 afterPropertiesSet 方法
- 调用自定义的 init-method 方法
- 调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
4. 使用阶段:
- Bean 可以被使用
5. 销毁阶段:
- 调用 DisposableBean 接口的 destroy 方法
- 调用自定义的 destroy-method 方法
代码示例:
@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String beanName;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
public LifecycleBean() {
System.out.println("1. 构造方法被调用");
}
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("2. BeanNameAware.setBeanName被调用: " + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("3. BeanFactoryAware.setBeanFactory被调用");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("4. ApplicationContextAware.setApplicationContext被调用");
}
@PostConstruct
public void postConstruct() {
System.out.println("5. @PostConstruct方法被调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6. InitializingBean.afterPropertiesSet被调用");
}
public void initMethod() {
System.out.println("7. 自定义init-method被调用");
}
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy方法被调用");
}
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean.destroy被调用");
}
public void destroyMethod() {
System.out.println("10. 自定义destroy-method被调用");
}
}
配置:
<bean id="lifecycleBean" class="com.example.LifecycleBean"
init-method="initMethod" destroy-method="destroyMethod"/>
Spring 事务管理
9. Spring 事务管理的核心概念是什么?
答案: Spring 事务管理的核心概念包括:
1. 事务属性(Transaction Attributes):
- 传播行为(Propagation):定义事务方法之间的调用关系
- 隔离级别(Isolation):定义事务的隔离程度
- 超时时间(Timeout):定义事务的超时时间
- 只读属性(Read-only):定义事务是否为只读
- 回滚规则(Rollback Rules):定义哪些异常会回滚事务
2. 事务传播行为:
@Transactional(propagation = Propagation.REQUIRED) // 默认,支持当前事务,如果没有则创建新事务
@Transactional(propagation = Propagation.REQUIRES_NEW) // 总是创建新事务
@Transactional(propagation = Propagation.SUPPORTS) // 支持当前事务,如果没有则以非事务方式执行
@Transactional(propagation = Propagation.NOT_SUPPORTED) // 以非事务方式执行
@Transactional(propagation = Propagation.MANDATORY) // 必须在事务中执行
@Transactional(propagation = Propagation.NEVER) // 不能在事务中执行
@Transactional(propagation = Propagation.NESTED) // 如果存在事务则嵌套执行
3. 事务隔离级别:
@Transactional(isolation = Isolation.DEFAULT) // 使用数据库默认隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED) // 读未提交
@Transactional(isolation = Isolation.READ_COMMITTED) // 读已提交
@Transactional(isolation = Isolation.REPEATABLE_READ) // 可重复读
@Transactional(isolation = Isolation.SERIALIZABLE) // 串行化
代码示例:
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private OrderDao orderDao;
// 外层事务
@Transactional(propagation = Propagation.REQUIRED)
public void createUserWithOrder(User user, Order order) {
// 保存用户
userDao.save(user);
// 调用内层事务方法
createOrder(order);
// 如果这里抛出异常,整个事务回滚
if (user.getName() == null) {
throw new RuntimeException("用户名不能为空");
}
}
// 内层事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createOrder(Order order) {
// 保存订单
orderDao.save(order);
// 如果这里抛出异常,只回滚订单,不影响用户
if (order.getAmount() <= 0) {
throw new RuntimeException("订单金额必须大于0");
}
}
}
10. Spring 事务的实现原理是什么?
答案: Spring 事务通过 AOP 和代理模式实现,具体原理如下:
1. 事务代理创建:
- Spring 在启动时扫描带有
@Transactional注解的类 - 为这些类创建代理对象
- 代理对象拦截方法调用,在方法执行前后添加事务逻辑
2. 事务拦截器链:
// 事务拦截器
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取事务属性
TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(
invocation.getMethod(), invocation.getThis().getClass());
// 获取事务管理器
PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, methodIdentification(invocation));
try {
// 执行目标方法
Object retVal = invocation.proceed();
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} catch (Throwable ex) {
// 回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
// 清理事务信息
cleanupTransactionInfo(txInfo);
}
}
}
3. 事务管理器:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
SpringMVC
11. SpringMVC 的核心组件和工作流程是什么?
答案: SpringMVC 是一个基于 MVC 模式的 Web 框架,其核心组件包括:
核心组件:
- DispatcherServlet:前端控制器,接收所有请求
- HandlerMapping:处理器映射器,根据 URL 找到对应的 Handler
- HandlerAdapter:处理器适配器,调用 Handler
- Handler:处理器,执行业务逻辑
- ViewResolver:视图解析器,解析视图名称
- View:视图,渲染页面
工作流程:
1. 用户发送请求到DispatcherServlet
2. DispatcherServlet调用HandlerMapping找到Handler
3. DispatcherServlet调用HandlerAdapter执行Handler
4. Handler执行完成后返回ModelAndView
5. DispatcherServlet调用ViewResolver解析视图
6. ViewResolver返回View
7. DispatcherServlet调用View渲染页面
8. 返回响应给用户
代码示例:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// GET请求,显示用户列表
@GetMapping("/list")
public String listUsers(Model model) {
List<User> users = userService.getAllUsers();
model.addAttribute("users", users);
return "user/list"; // 视图名称
}
// POST请求,创建用户
@PostMapping("/create")
@ResponseBody
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
User savedUser = userService.createUser(user);
return ResponseEntity.ok(savedUser);
}
// PUT请求,更新用户
@PutMapping("/{id}")
@ResponseBody
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
User updatedUser = userService.updateUser(user);
return ResponseEntity.ok(updatedUser);
}
// DELETE请求,删除用户
@DeleteMapping("/{id}")
@ResponseBody
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.ok().build();
}
}
12. SpringMVC 中的注解有哪些?如何使用?
答案: SpringMVC 提供了丰富的注解:
1. 类级别注解:
@Controller // 标识这是一个控制器
@RestController // @Controller + @ResponseBody,用于REST API
@RequestMapping("/api") // 类级别的路径映射
2. 方法级别注解:
// 请求映射
@GetMapping("/users") // GET请求
@PostMapping("/users") // POST请求
@PutMapping("/users/{id}") // PUT请求
@DeleteM
