java测试题(下)
1. Spring 核心概念
1.1 如何理解 Spring DI?
DI(依赖注入) 是 IoC(控制反转) 的具体实现方式,由 Spring 容器在运行时通过以下方式自动注入依赖:
构造器注入(推荐)
Setter 注入
字段注入(不推荐,因测试困难)
开发者无需手动
new
依赖对象,降低耦合度。
1.2 基于注解配置作用域与延迟加载
注解 | 作用域示例 | 描述 |
---|---|---|
@Scope | @Scope("singleton") (默认) | 单例模式,全局唯一实例 |
@Scope("prototype") | 每次请求创建新实例 | |
@Scope(value="request") | 每个 HTTP 请求一个实例(Web 环境) | |
@Lazy | @Lazy(true) | 延迟初始化,首次使用时创建 Bean |
示例代码:
@Component
@Scope("prototype")
@Lazy
public class MyBean { }
1.3 BeanFactory vs ApplicationContext
特性 | BeanFactory | ApplicationContext |
---|---|---|
加载时机 | 懒加载(调用 getBean() 时) | 预加载(容器启动时初始化所有单例 Bean) |
高级功能 | 无 | 支持国际化、事件传播、AOP 等 |
适用场景 | 资源受限环境(如移动设备) | 企业级应用(99% 场景使用) |
1.4 Spring Bean 生命周期
实例化:通过反射创建 Bean 实例。
属性赋值:DI 注入依赖。
初始化:
调用
@PostConstruct
方法实现
InitializingBean
的afterPropertiesSet()
使用:容器中的 Bean 被调用。
销毁:
调用
@PreDestroy
方法实现
DisposableBean
的destroy()
1.5 Bean 作用域对比
作用域 | 描述 | 适用场景 |
---|---|---|
singleton | 默认作用域,容器内唯一实例 | 无状态服务(如工具类、DAO) |
prototype | 每次请求创建新实例 | 有状态对象(如用户会话) |
request | 每个 HTTP 请求一个实例(Web 环境) | 表单数据、请求级缓存 |
session | 每个 HTTP Session 一个实例 | 用户登录状态、购物车 |
application | 整个 Web 应用共享一个实例(ServletContext) | 全局配置、缓存 |
1.6 设计模式应用
模式 | 示例 |
---|---|
工厂模式 | BeanFactory 创建 Bean 实例 |
单例模式 | 默认作用域 singleton |
代理模式 | AOP 动态代理(JDK/CGLIB) |
观察者模式 | 事件监听(ApplicationListener ) |
模板方法模式 | JdbcTemplate 、RestTemplate |
1.7 Controller 并发安全
无状态设计:避免定义成员变量。
线程安全:所有数据通过方法参数或局部变量传递。
示例
@RestController public class SafeController {// 正确:无成员变量@GetMapping("/test")public String test(@RequestParam String param) {return "Result: " + param;} }
2. Spring MVC
2.1 处理流程
DispatcherServlet 接收请求。
HandlerMapping 根据
@RequestMapping
匹配 Controller。HandlerAdapter 调用 Controller 方法。
Controller 返回
ModelAndView
或 JSON(@ResponseBody
)。ViewResolver 解析视图(如 JSP、Thymeleaf)。
渲染视图 并返回响应。
2.2 与 AJAX 交互
后端:使用
@RestController
+@ResponseBody
返回 JSON。前端:AJAX 请求示例(jQuery)
$.get("/api/user/1", function(data) {console.log(data.name); });
2.3 与 Struts2 对比
特性 | Spring MVC | Struts2 |
---|---|---|
控制器 | 单例(线程安全) | 多例(每个请求一个 Action) |
配置 | 注解驱动(零 XML) | 基于 XML 和 OGNL |
性能 | 更高(无拦截器栈) | 较低(复杂 OGNL 解析) |
生态 | 与 Spring Boot 无缝集成 | 社区已停滞 |
3. Spring 事务管理
3.1 两种方式对比
方式 | 优点 | 缺点 |
---|---|---|
声明式 | 零侵入(@Transactional ) | 学习 AOP 和配置复杂 |
编程式 | 精确控制(TransactionTemplate ) | 代码冗余、维护困难 |
3.2 优势
传播行为:支持
REQUIRED
、REQUIRES_NEW
等 7 种策略。隔离级别:
READ_COMMITTED
、SERIALIZABLE
等。多技术兼容:统一 JDBC、JPA、Hibernate 事务。
测试支持:测试时自动回滚(
@Rollback
)。
4. MyBatis
4.1 动态 SQL 解决的问题
SQL 注入:
#{}
预编译参数(如#{id}
)。代码冗余:
<if>
、<choose>
等标签动态拼接 SQL。复杂查询:
<foreach>
处理IN
语句。
示例:
<select id="findUser" resultType="User">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if></where>
</select>
4.2 缓存机制
类型 | 范围 | 生命周期 | 配置方式 |
---|---|---|---|
一级缓存 | SqlSession | 同一会话内有效,默认开启 | 无需配置 |
二级缓存 | Mapper | 跨 SqlSession,需手动开启 | <cache/> 或注解 @CacheNamespace |
4.3 接口绑定
原理:通过 JDK 动态代理为 Mapper 接口生成实现类。
好处:
SQL 与 Java 代码分离(XML 或注解)。
无需手动实现 DAO(如 JDBC 模板)。
支持动态 SQL 和结果映射。
4.4 JDBC 不足与 MyBatis 解决
JDBC 问题 | MyBatis 解决方案 |
---|---|
冗余代码 | 封装模板(SqlSessionTemplate ) |
手动事务管理 | 集成 Spring 声明式事务 |
无连接池 | 集成 HikariCP、Druid |
手动 ORM | 自动结果映射(@Results ) |
4.5 优缺点
优点 | 缺点 |
---|---|
SQL 可控性强 | 需手写 SQL |
轻量级(无过度封装) | 二级缓存配置复杂 |
性能优化友好(如延迟加载) | XML 配置繁琐(可用注解) |
5. Shiro 权限管理
5.1 认证与授权流程
认证:
Subject.login()
提交凭证(如用户名/密码)。Realm.doGetAuthenticationInfo()
验证身份。成功后将用户信息存入
Session
。
授权:
Realm.doGetAuthorizationInfo()
加载角色和权限。通过注解
@RequiresRoles("admin")
或标签<shiro:hasPermission>
校验权限。
6. 其他常见问题
6.1 Bean 工厂底层机制
反射:通过
Class.forName()
实例化 Bean。工厂模式:
BeanFactory
管理对象生命周期。动态代理:AOP 生成代理对象(JDK/CGLIB)。
资源释放:调用
DisposableBean.destroy()
或@PreDestroy
避免内存泄漏。
6.2 内存泄漏
定义:已分配内存无法被 GC 回收(如未关闭的
Connection
、ThreadLocal
未清理)。预防:使用 try-with-resources、Spring 的
DisposableBean