SSM框架实训测试题整理2
十一. BeanFactory 和 ApplicationContext 有什么区别?
| 特性 | BeanFactory | ApplicationContext |
|---|---|---|
| 定位 | Spring框架最底层的、最基本的核心接口。 | BeanFactory 的子接口,提供了更多的企业级功能。 |
| Bean的加载时机 | 延迟加载。只有在第一次使用getBean()时才会创建Bean。 |
默认立即加载。容器启动时就会创建并配置所有的单例Bean(非懒加载的)。 |
| 功能 | 功能相对基础,主要负责Bean的定义、创建和访问。 | 在BeanFactory基础上,额外提供了: • 国际化的消息解析(MessageSource)。 • 资源访问(如文件、URL)。 • 事件发布(ApplicationEventPublisher)。 • AOP集成。 • 更方便的与Web应用集成。 |
| 使用场景 | 在资源受限的移动设备或Applet中,内存占用非常关键时。 | 绝大多数场景下的标准选择,如Java SE桌面应用、Web应用等。 |
总结: ApplicationContext 是 BeanFactory 的完整超集。除非有特殊的内存限制,否则总是应该使用 ApplicationContext。
十二. 请解释Spring Bean的生命周期?
对于一个普通的Spring Bean,其生命周期可以概括为下图所示的完整流程:

十三.Spring Bean的作用域之间有什么区别?
| 作用域 | 描述 | 使用场景 |
|---|---|---|
| singleton | (默认)每个Spring IoC容器中只有一个Bean实例。 | 无状态的Bean,如Service、Dao等。 |
| prototype | 每次请求(注入或getBean())都会创建一个新的Bean实例。 |
有状态的Bean,如每个请求需要独立状态的对象。 |
| request | 每个HTTP请求创建一个新的Bean。 | 用于存储与一次请求相关的信息。 |
| session | 每个HTTP Session创建一个新的Bean。 | 用于存储与用户会话相关的信息,如用户登录信息。 |
| application | 每个ServletContext生命周期内一个Bean。 | 用于存储全局的、应用级别的信息。 |
| websocket | 每个WebSocket会话内一个Bean。 | 用于WebSocket通信。 |
十四. 使用Spring框架的好处是什么?
-
轻量级与非侵入式: Spring本身是轻量级的,并且其核心容器对业务对象几乎没有侵入性(不需要实现特定接口)。
-
控制反转(IoC)与依赖注入(DI): 这是Spring的核心。通过IoC容器管理对象的生命周期和依赖关系,实现了组件之间的解耦,使得代码更加灵活、可测试和可维护。
-
面向切面编程(AOP): 将横切关注点(如日志、事务、安全)与核心业务逻辑分离,提高了代码的模块化和可重用性。
-
强大的事务管理: 提供了一致性的事务管理抽象,支持声明式事务和编程式事务,极大地简化了数据库事务的处理。
-
便捷的集成能力: 像一个“粘合剂”,可以方便地集成其他优秀的框架和技术,如Hibernate、MyBatis、JMS、Quartz等。
-
强大的MVC框架: Spring MVC提供了一个功能强大、高度可配置的Web框架。
-
异常处理: 提供了一套一致的、未检查的异常处理哲学。
-
测试支持: 提供了专门的测试模块,支持单元测试和集成测试。
十五.Spring 中用到了那些设计模式?
-
工厂模式:
BeanFactory和ApplicationContext是工厂模式的典型实现,用于创建和管理Bean。 -
单例模式: Spring管理的Bean默认就是单例的。
-
代理模式: Spring AOP 的核心就是使用JDK动态代理或CGLIB字节码生成技术来创建代理对象。
-
模板方法模式:
JdbcTemplate,RestTemplate等,它们定义了算法的骨架,而将一些步骤延迟到子类或由回调函数实现。 -
观察者模式: Spring的事件驱动模型(
ApplicationEvent,ApplicationListener)就是观察者模式的实现。 -
适配器模式: 在Spring MVC中,
HandlerAdapter使得多种类型的Controller(如@Controller,HttpRequestHandler)能够被统一处理。 -
策略模式: 在资源访问时,
Resource接口是策略接口,不同的实现类(ClassPathResource,UrlResource)是不同的策略。 -
装饰者模式: 在处理数据源等场景时,Spring经常使用装饰者模式来增强功能。
十六.Spring 如何保证 Controller 并发的安全?
Spring MVC的Controller默认是单例的,但它是线程安全的吗?
答案是:这取决于Controller的状态。
-
如果Controller是无状态的: 即Controller类中没有可变的成员变量(实例变量),那么它就是线程安全的。这是推荐的、绝大多数情况下的做法。
java
@Controller // 线程安全:没有实例变量,所有操作都在方法栈帧内完成。 public class MyController { @Autowired private MyService myService; // 这是一个依赖,本身也应该是单例且无状态的。 @RequestMapping("/test") public String test() { myService.doSomething(); // 安全 return "view"; } } -
如果Controller是有状态的: 即Controller类中定义了可变的实例变量,那么它就不是线程安全的,因为多个线程会共享并修改这个变量。
java
@Controller // 非线程安全! public class UnsafeController { private int count = 0; // 可变实例变量 @RequestMapping("/count") public String count() { count++; // 非原子操作,存在竞态条件 return "view"; } }
如何保证并发安全?
-
最佳实践:保持无状态: 不要在Controller中定义实例变量。所有需要的数据都通过方法参数传入,在方法内部处理。
-
如果需要状态,改变作用域: 将Controller的作用域改为
@Scope("prototype"),这样每次请求都会创建一个新的Controller实例。但这种方法会增加GC负担,一般不推荐。 -
使用ThreadLocal: 可以将一些需要在线程内共享的数据(如当前用户信息)存储在ThreadLocal中。但需要确保在使用后及时清理,防止内存泄漏。
-
避免在Controller中定义非静态、非final的字段。
十七.在 Spring中如何注入一个java集合?
Spring可以通过XML和注解两种方式注入集合。
1. XML配置方式:
使用 <list>, <set>, <map>, <props> (对应Properties) 标签。
xml
<bean id="collectionBean" class="com.example.CollectionBean">
<property name="myList">
<list>
<value>Apple</value>
<ref bean="someOtherBean"/>
<value>Banana</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value-ref="someOtherBean"/>
</map>
</property>
<property name="mySet">
<set>
<value>Value1</value>
<value>Value2</value>
</set>
</property>
</bean>
2. 注解方式(结合Java配置类):
在配置类中使用 @Bean 方法返回集合。
java
@Configuration
public class AppConfig {
@Bean
public List<String> myList() {
return Arrays.asList("A", "B", "C");
}
@Bean
public MyService myService() {
MyService service = new MyServiceImpl();
service.setMyList(myList()); // 注入list
return service;
}
}
或者,在属性上使用 @Autowired 或 @Resource 来自动装配一个已定义的集合Bean。
十八. Spring支持的事务管理类型?
-
编程式事务管理: 通过编写代码(如使用
TransactionTemplate或直接使用PlatformTransactionManager)来精确控制事务的边界。 -
声明式事务管理(最常用): 通过配置(XML或
@Transactional注解)来定义事务规则,由Spring容器通过AOP在运行时自动管理事务。这是非侵入式的,推荐使用。
十九.Spring框架的事务管理有哪些优点?
-
提供一致的编程模型: 无论使用JDBC、Hibernate、JPA还是其他数据访问技术,都使用相同的事务管理API和配置方式。
-
支持声明式事务管理: 这是最大的优点,使事务管理与业务代码解耦,开发更简单。
-
比复杂的事务API(如JTA)更简单: Spring提供了一个简单而强大的抽象层。
-
与Spring数据访问抽象层完美集成: 与JdbcTemplate、HibernateTemplate等无缝协作。
-
支持多种事务传播行为: 可以精细地控制事务的边界和行为。
二十.Spring MVC的主要组件?
-
DispatcherServlet: 前端控制器,是所有请求的入口,负责协调各个组件。
-
HandlerMapping: 根据请求的URL,找到对应的处理器(Controller)。
-
HandlerAdapter: 实际调用处理器方法,并处理参数绑定、方法调用、返回值处理等。
-
Controller: 处理器,执行具体的业务逻辑。
-
ViewResolver: 根据控制器返回的逻辑视图名,解析出实际的View对象。
-
View: 负责渲染视图,将模型数据展示给用户(如JSP、Thymeleaf模板)。
-
HandlerExceptionResolver: 处理请求过程中抛出的异常。
-
MultipartResolver: 处理文件上传请求。
二十一. SpringMvc怎么和AJAX相互调用的?
主要通过返回JSON或XML格式的数据来实现。
-
后端(Spring MVC Controller):
-
使用
@RestController注解,或者在有@Controller注解的类的方法上使用@ResponseBody。 -
方法直接返回Java对象(如POJO、List、Map等)。
-
配置消息转换器(如
MappingJackson2HttpMessageConverter),Spring会自动使用Jackson库将返回的对象转换为JSON字符串。
java
@RestController public class UserController { @RequestMapping("/getUser") public User getUser(@RequestParam Long id) { User user = userService.findById(id); return user; // 自动转换为JSON } } -
-
前端(AJAX调用):
-
使用jQuery、Axios、Fetch API等发起AJAX请求。
-
在成功回调函数中处理返回的JSON数据。
javascript
$.ajax({ type: "GET", url: "/getUser", data: { id: 123 }, success: function(user) { console.log("User name: " + user.name); } }); -
二十二.mybatis的缓存机制,一级,二级介绍一下?
MyBatis提供了两级缓存来提高查询性能。
| 特性 | 一级缓存 | 二级缓存 |
|---|---|---|
| 作用域 | SqlSession 级别。 | Mapper (Namespace) 级别。 |
| 默认开启 | 是。 | 否,需要在配置文件中显式开启(<setting name="cacheEnabled" value="true"/>)并在Mapper.xml中配置 <cache/>。 |
| 共享性 | 同一个SqlSession内共享。 | 同一个namespace下的所有SqlSession共享。 |
| 失效时机 | 当执行 INSERT、UPDATE、DELETE 操作,或调用 sqlSession.clearCache(),或关闭SqlSession时,一级缓存会清空。 |
当执行同namespace下的增删改操作时,二级缓存会被清空。也可以通过配置设置刷新间隔等。 |
| 存储结构 | 内存中的一个简单HashMap。 | 可以配置使用不同的缓存实现,如Ehcache、Redis等。 |
工作顺序: 当执行一个查询时,MyBatis会先查找二级缓存,再查找一级缓存,如果都没有,最后才去查询数据库。
二十三.Mybatis的基本工作流程?
-
加载配置: MyBatis 从配置文件(
mybatis-config.xml)和映射文件(*Mapper.xml)中加载全局配置信息和 SQL 映射信息,构建出SqlSessionFactory对象。 -
创建 SqlSession: 通过
SqlSessionFactory创建一个SqlSession对象,它代表一次数据库会话。 -
获取 Mapper 接口代理: 通过
SqlSession的getMapper(Class<T> type)方法,获取 Mapper 接口的动态代理对象。 -
执行 SQL: 调用 Mapper 接口的方法。MyBatis 底层会根据方法名找到对应的 SQL 语句,设置参数,然后执行 SQL。
-
操作数据库:
SqlSession将 SQL 操作委托给Executor执行器。Executor通过StatementHandler操作Statement对象与数据库交互。 -
处理结果:
Executor通过ResultSetHandler将 JDBC 返回的ResultSet结果集转换为指定的 Java 对象(POJO、List、Map等)。 -
提交/回滚事务: 如果设置了手动提交,需要调用
sqlSession.commit()。如果发生异常,则回滚事务。 -
关闭 SqlSession: 最终,关闭
SqlSession,释放数据库连接等资源。
核心对象流程: SqlSessionFactory -> SqlSession -> Executor -> MappedStatement -> 数据库
二十四. 什么是MyBatis的接口绑定,有什么好处?
-
定义: 接口绑定是指 MyBatis 允许我们只定义一个 Mapper 接口(通常是 Java 接口),而不需要编写其实现类。MyBatis 会使用 JDK 动态代理 在运行时为这个接口生成一个代理对象。
-
绑定方式:
-
XML 配置绑定: 在 XML 映射文件中定义命名空间 (
namespace) 为接口的全限定名,SQL 语句的id为接口的方法名。 -
注解绑定: 在接口的方法上直接使用
@Select、@Update等注解来编写 SQL。
-
-
好处:
-
代码更简洁: 无需编写繁琐的 DAO 实现类。
-
类型安全: 方法调用是类型安全的,如果方法名或参数不匹配,会在编译期就报错(相比起基于字符串的 SQL ID 调用)。
-
IDE 支持好: 可以被 IDE 的自动补全、重构等功能很好地支持。
-
解耦: 将 Java 接口与 SQL 实现清晰地分离开。
-
二十五. MyBatis的编程步骤?
-
创建 SqlSessionFactory:
java
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
-
通过 SqlSessionFactory 创建 SqlSession。
java
SqlSession session = sqlSessionFactory.openSession();
-
通过 SqlSession 执行数据库操作(两种方式):
-
旧方式(不推荐): 直接调用
session.selectOne(),session.insert()等方法,通过字符串指定 SQL ID。 -
推荐方式: 获取 Mapper 接口的代理对象,然后调用其方法。
java
UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectUserById(1);
-
-
提交事务:
session.commit();(如果设置为手动提交)。 -
关闭会话:
session.close();。
二十六. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?
| JDBC 不足 | MyBatis 解决方案 |
|---|---|
| 1. 代码繁琐,大量重复样板代码 (创建连接、声明Statement、处理结果集、关闭资源) | 自动化: 封装了底层操作,开发者只需关注 SQL 和映射。 |
| 2. 硬编码 (SQL、数据库连接参数写在代码中) | 配置化: SQL 和配置写在 XML 或注解中,与代码解耦。 |
3. 手动设置参数和映射结果集 (需要手动将 ResultSet 字段一个个取出并设置到对象属性中) |
自动映射: 通过反射或自定义 ResultMap,自动完成 POJO 的属性填充。 |
| 4. 数据库连接管理繁琐 | 集成连接池: 方便地与各种连接池(如Druid, HikariCP)集成,管理连接生命周期。 |
| 5. 功能单一 (不支持缓存、延迟加载等高级特性) | 提供高级功能: 内置一级/二级缓存、延迟加载、插件机制等。 |
二十七. MyBatis的优缺点?
优点:
-
SQL 灵活可控: 开发者可以编写和优化 SQL,特别适合复杂查询和性能要求高的场景。
-
学习成本低: 相对于 Hibernate 等全自动 ORM,更容易上手。
-
与 JDBC 相比代码量大大减少。
-
很好的与各种数据库兼容(因为 SQL 是自己写的)。
-
提供了映射标签,支持对象与数据库的字段映射。
-
提供了 XML 标签,支持编写动态 SQL。
缺点:
-
SQL 工作量大: 当字段多、关联表多时,编写 SQL 和映射文件是负担。
-
数据库依赖性高: 由于 SQL 是自己写的,数据库切换成本比 Hibernate 高。
-
半自动: 需要自己编写 SQL,不像全自动 ORM 那样完全屏蔽数据库差异。
二十八. 谈谈你对SpringMVC的理解?
Spring MVC 是一个基于 Java 的、实现了 MVC 设计模式的请求驱动类型的轻量级 Web 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。它支持 RESTful 编程风格的请求。
核心思想: 通过 DispatcherServlet 这个“总调度员”,将复杂的 Web 应用请求处理流程标准化、组件化,使得各组件(控制器、视图解析器等)职责单一,松散耦合,易于扩展和测试。
二十九. 简述Mybatis的插件运行原理,以及如何编写一个插件?
-
运行原理: MyBatis 的插件本质上是一种拦截器,使用 JDK 动态代理。它允许拦截并增强 MyBatis 核心组件的方法调用。
MyBatis 有四大核心对象可以被拦截:-
Executor(执行器) -
ParameterHandler(参数处理器) -
ResultSetHandler(结果集处理器) -
StatementHandler(语句处理器)
插件会为这些目标对象创建一个代理对象。当调用代理对象的方法时,会先执行插件中定义的拦截逻辑。
-
-
编写步骤:
-
实现
Interceptor接口,并重写intercept方法(在此编写增强逻辑)。 -
使用
@Intercepts和@Signature注解指定要拦截哪个对象的哪个方法。 -
在
mybatis-config.xml中注册这个插件。
示例(分页插件原理):
java
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) public class MyPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("在执行SQL之前做一些事情..."); // 继续执行原方法 Object result = invocation.proceed(); System.out.println("在执行SQL之后做一些事情..."); return result; } } -
三十. Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
-
支持。
-
实现原理: 基于 动态代理。
-
配置: 在全局配置中开启延迟加载
lazyLoadingEnabled=true。 -
触发: 当查询主对象时,MyBatis 只执行主 SQL。对于关联对象(一对一、一对多),MyBatis 不会立即查询,而是返回一个代理对象。
-
加载时机: 当程序第一次真正访问这个代理对象的某个方法(如
getter方法)时,代理对象会触发一次新的 SQL 查询,去数据库加载真正的关联数据。
-
例如: 查询 Order 对象,它有一个 User 属性。默认只查 Order,当调用 order.getUser().getName() 时,才会去执行查询 User 的 SQL。
更多推荐
所有评论(0)