当前位置: 首页 > news >正文

java测试题(ssm框架)

一、Spring MVC

  1. Q: 谈谈你对Spring MVC的理解?

    • A: Spring MVC是基于Java的轻量级Web框架,是Spring框架的一个模块。它采用了经典的MVC (Model-View-Controller) 设计模式,实现了业务逻辑、数据和视图的清晰解耦。其核心是围绕DispatcherServlet前端控制器)构建的请求驱动模型。通过HandlerMapping(处理器映射)、HandlerAdapter(处理器适配器)、ViewResolver(视图解析器)等核心组件协作处理HTTP请求。它支持强大的功能,如灵活的视图技术(JSP, Thymeleaf, FreeMarker等)、全局异常处理文件上传数据绑定验证等。

    • 主要优势:

      • 松耦合: 深度依赖Spring的IoC (控制反转) / DI (依赖注入) 容器管理组件。

      • 灵活性: 支持多种视图技术,易于扩展(如自定义拦截器HandlerInterceptor)。

      • 现代性: 深度支持RESTful 风格开发,注解驱动(如@Controller@RequestMapping)配置简洁。

      • 集成性: 与Spring Boot无缝集成,开箱即用。

      • 高性能: 相比Struts2等框架,设计更简洁高效。

      • 扩展性: 提供DeferredResult/Callable支持异步请求处理,并通过Spring WebFlux支持响应式编程模型。

    • 设计哲学: 体现了“约定优于配置”的思想,简化开发。凭借其成熟性、灵活性和强大的Spring生态整合能力,Spring MVC已成为企业级Web应用开发的主流选择。

  2. Q: 介绍一下Spring MVC的工作流程?

    • A: Spring MVC的核心工作流程如下:

      1. DispatcherServlet 接收请求: 用户发起HTTP请求,由配置的前端控制器DispatcherServlet捕获。

      2. HandlerMapping 查找处理器: DispatcherServlet 查询注册的HandlerMapping,根据请求URL找到对应的Handler(通常是@Controller注解标记类中的一个具体方法)。

      3. HandlerAdapter 执行处理器: DispatcherServlet 通过HandlerAdapter适配器来执行找到的Handler方法。适配器负责处理方法参数绑定(将请求参数、路径变量、Session属性、Model对象等注入到方法参数中)和返回值处理

      4. Controller 执行业务逻辑: Handler方法(即Controller方法)执行业务逻辑,通常会访问Service层,并最终返回一个结果(可能是视图名称StringModelAndView对象、@ResponseBody注解的Java对象等)。

      5. 处理返回结果:

        • 如果返回视图名称或ModelAndViewDispatcherServlet会调用ViewResolver视图解析器将逻辑视图名解析为具体的View对象(如JSP, Thymeleaf模板)。

        • 如果方法有@ResponseBody注解或返回类型是ResponseEntity等,则使用HttpMessageConverter将返回值直接写入HTTP响应体(如JSON/XML)。

      6. View 渲染: View对象负责渲染模型数据(由Controller放入ModelModelMap中的数据),生成最终的响应内容(如HTML)。

      7. 响应返回: 将渲染结果返回给客户端。

  3. Q: 如果你也用过Struts2,简单介绍下Spring MVC和Struts2的区别有哪些?

    • A: Spring MVC与Struts2的核心区别在于架构设计开发模式

      • 前端控制器: Spring MVC基于Servlet (DispatcherServlet),Struts2基于Filter (StrutsPrepareAndExecuteFilter / 早期的 FilterDispatcher)。

      • 映射方式: Spring MVC支持方法级映射(@RequestMapping注解在方法上),更灵活,天然适合RESTful。Struts2是Action类级映射(通常一个URL对应一个Action类),需要在XML或注解中指定方法名。

      • 参数绑定: Spring MVC提供灵活强大的参数绑定机制(支持路径变量@PathVariable、请求参数@RequestParam、模型属性@ModelAttribute等),处理简单直观。Struts2主要依赖OGNL表达式Setter/Getter进行参数注入。

      • IoC容器: Spring MVC深度集成Spring IoC容器,Controller及其他组件都是Spring Bean,享受依赖注入、AOP等所有Spring特性。Struts2有自身的IoC容器,但功能不如Spring强大,且与Spring整合需要额外配置。

      • 设计理念: Spring MVC更轻量简洁,更符合现代Java Web开发习惯。Struts2相对重量级,配置较繁琐。

      • 性能: 普遍认为Spring MVC的性能优于Struts2,尤其在请求处理速度和内存占用方面。

      • 线程模型: Spring MVC默认Controller是单例的(线程安全需开发者注意)。Struts2默认每次请求创建一个新的Action实例

      • 视图技术: 两者都支持多种视图技术,但Spring MVC与新兴模板引擎(Thymeleaf)的整合通常更流畅。

      • 社区与趋势: Spring MVC(及其在Spring Boot中的形态)是目前绝对的主流,社区活跃,生态丰富。Struts2因历史安全漏洞、架构相对陈旧等原因,已逐渐被淘汰,主要用于维护遗留系统。

  4. Q: 怎么样把数据放入Session里面?

    • A: 在Spring MVC的Controller方法中,可以通过以下方式将数据放入HttpSession:

      1. 注入HttpServletRequest

        java

        @RequestMapping("/setSession")
        public String setSessionData(HttpServletRequest request) {request.getSession().setAttribute("key", "value"); // 使用request获取sessionreturn "view";
        }
      2. 直接注入HttpSession

        java

        @RequestMapping("/setSession")
        public String setSessionData(HttpSession session) { // 直接注入sessionsession.setAttribute("key", "value");return "view";
        }
      3. 使用@SessionAttributes注解 (Controller类级别): 该注解主要用于在请求之间Model中的特定属性临时存储在Session中(通常用于表单对象跨请求),并非通用的Session存取方式。通用数据存取推荐前两种方式。

二、MyBatis

  1. Q: 简述Mybatis的插件运行原理,以及如何编写一个插件?

    • A:

      • 原理: MyBatis插件的核心原理是 责任链模式 + 动态代理。MyBatis允许在四大核心对象 (ExecutorStatementHandlerParameterHandlerResultSetHandler) 的方法执行前后进行拦截。当配置了插件后,MyBatis会使用JDK动态代理(如果对象实现了接口)或CGLIB动态代理(如果对象没实现接口)为这些核心对象创建代理对象。当调用代理对象的方法时,会先经过配置的所有插件的intercept()方法。在intercept()方法内部,开发者可以编写自定义逻辑,然后通过Invocation.proceed()方法将调用传递给责任链中的下一个插件或最终的目标方法。

      • 编写插件:

        1. 实现MyBatis提供的Interceptor接口。

        2. 重写intercept(Invocation invocation)方法,在此方法中编写拦截逻辑。可以通过invocation.getTarget()获取被拦截的目标对象,invocation.getMethod()获取被拦截的方法,invocation.getArgs()获取方法参数。调用invocation.proceed()执行原方法。

        3. 重写plugin(Object target)方法,通常使用Plugin.wrap(target, this)来方便地创建代理对象。

        4. 重写setProperties(Properties properties)方法,用于接收插件配置参数(如果在xml中配置了<property>)。

        5. 使用@Intercepts@Signature注解(或在XML中配置<plugins>)指定要拦截的方法以及方法参数类型

        6. 在MyBatis的核心配置文件(mybatis-config.xml)中注册该插件。

  2. Q: Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

    • A:

      • 支持。 MyBatis支持关联对象(一对一<association>、一对多<collection>)的延迟加载(懒加载)。

      • 原理: 核心是 动态代理 + 拦截机制

        1. 当执行查询主对象的SQL时,MyBatis会将查询到的结果映射到主对象。

        2. 对于配置了延迟加载的关联对象属性,MyBatis不会立即执行关联SQL去查询数据库,而是为该属性创建一个动态代理对象(如ProxyCglibProxyFactory生成的代理)。

        3. 当程序首次调用这个代理对象的任何方法(如getXXX())时,代理对象会拦截这次调用。

        4. 拦截器触发关联SQL查询的执行,从数据库中加载关联对象的真实数据

        5. 加载完成后,MyBatis会用加载到的真实对象替换掉原来的代理对象(或者通过代理对象持有真实对象的引用)。

        6. 后续再调用该属性的方法时,将直接操作已经加载完成的真实对象数据,不再触发SQL查询。

      • 关键配置: 在MyBatis全局配置(mybatis-config.xml)或映射文件中,通过lazyLoadingEnabled=true开启全局延迟加载,aggressiveLazyLoading=false(推荐)防止“侵入性”加载(访问一个延迟属性就加载所有延迟属性)。

  3. Q: Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别?

    • A:

      • 能。 MyBatis非常擅长处理对象关联映射。

      • 实现方式: 主要有两种:

        1. 嵌套查询 (Nested Select):

          • 定义:执行一条主查询SQL获取主对象结果集。然后,对于结果集中的每一行(即每一个主对象),根据配置的<association><collection>标签中的select属性指定的另一个Mapper语句的ID,再发起额外的SQL查询去加载其关联对象。

          • 特点:

            • 会产生 N+1 查询问题(1条主查询 + N条关联查询,N是主查询结果集行数)。

            • SQL语句相对简单

            • 适用于关联对象数据量较小,或者关联查询的条件比较复杂(不适合用JOIN写)的场景。

            • 可以配合延迟加载使用。

        2. 嵌套结果 (Nested Results):

          • 定义:编写一条复杂的联合查询SQL (JOIN),一次性查询出主对象及其关联对象的所有字段。然后,在ResultMap中使用<association><collection>标签的resultMap属性(或内联<result>)来手动定义如何从联合查询的大结果集中拆分出关联对象的字段并进行映射

          • 特点:

            • 只有一条SQL,避免了N+1问题,性能通常更好

            • SQL语句相对复杂(需要写JOIN)。

            • 适用于主查询结果集数据量较大,且关联对象字段较少、结构相对简单的场景。

            • 无法直接使用延迟加载(因为数据是一次性查出来的)。

      • 主要区别总结:

        特性嵌套查询 (Nested Select)嵌套结果 (Nested Results)
        SQL数量1 (主) + N (关联)1 (联合查询)
        性能可能存在 N+1 问题,效率较低效率较高 (单次查询)
        SQL复杂度主SQL和关联SQL相对简单SQL较复杂 (需JOIN)
        适用场景关联数据少/查询条件复杂主数据量大/关联字段少且简单
        延迟加载支持不支持
  4. Q: Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

    • A:

      • 封装过程: 主要由ResultSetHandler组件完成。

        1. 执行SQL后,获取JDBC ResultSet结果集。

        2. 读取ResultSet元数据ResultSetMetaData),获取列名、列类型等信息。

        3. 根据Mapper中配置的结果映射规则resultTyperesultMap),确定目标Java类型。

        4. 通过反射创建目标Java对象的实例。

        5. 遍历结果集的每一行:

          • 根据列名(或resultMap中指定的column)查找目标对象中对应的属性名(或resultMap中指定的property)。

          • 利用反射找到属性的Setter方法(或直接访问字段,如果配置允许)。

          • ResultSet中当前行对应列的值取出,进行必要的类型转换(MyBatis内置了大量TypeHandler处理基础类型、日期等)。

          • 调用Setter方法(或直接设置字段值)将转换后的值注入到目标对象中。

        6. 将填充好数据的对象添加到返回的集合(List)或作为单个对象返回。

      • 映射形式:

        1. resultType (自动映射):

          • 指定一个简单的Java类型(如基本类型包装类、String)或POJO类的全限定名。

          • MyBatis会基于列名与属性名的匹配规则(开启mapUnderscoreToCamelCase可启用下划线转驼峰)自动进行映射。要求数据库列名(或别名)与POJO属性名严格匹配(忽略大小写?通常不忽略,取决于DB驱动)。无法处理复杂关系(如关联对象)。

        2. resultMap (自定义映射):

          • 定义一个<resultMap>标签,在其中显式、精细地指定数据库列(column)与Java对象属性(property)之间的映射关系。

          • 功能最强大,可以处理:

            • 列名与属性名不一致。

            • 复杂类型属性(如关联对象<association><collection>)。

            • 构造函数映射(<constructor>)。

            • 鉴别器(<discriminator>)实现继承映射。

            • 使用<id>标签标识主键提升性能。

        3. 构造函数映射 (<constructor> within <resultMap>):

          • resultMap的一部分。

          • 用于当目标对象没有无参构造器,或者你想通过构造器注入结果值而非Setter注入时。

          • <resultMap>中使用<constructor>标签,内部通过<idArg>(主键参数)和<arg>(普通参数)标签指定构造器参数对应的数据库列。

  5. Q: Mybatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?

    • A: B标签可以定义在A标签的前面或后面。 因为MyBatis在解析整个XML映射文件时,会先将所有的<sql>片段(B标签)和<select>/<insert>/<update>/<delete>等语句(A标签)一次性加载到内存中,构建一个完整的DOM树或内部数据结构。之后,在处理<include>标签引用<sql>片段时,它只需要根据refid在这个已经加载好的全局结构中找到对应的片段进行替换即可。所以定义顺序不影响解析和引用。

  6. Q: MyBatis里面的动态Sql是怎么设定的?用什么语法?

    • A:

      • 设定: 动态SQL主要在Mapper XML映射文件中定义(也可以在注解中使用@SelectProvider等实现,但XML方式更强大常用)。通过使用MyBatis提供的一系列特殊标签OGNL (Object-Graph Navigation Language) 表达式来实现。

      • 核心标签:

        • <if> 条件判断。test属性写OGNL表达式,表达式结果为true时,包含其中的SQL片段才会被拼接。

          xml

          <if test="title != null"> AND title = #{title} </if>
        • <choose> / <when> / <otherwise> 类似Java的switch-case-default,实现多分支选择。

          xml

          <choose><when test="state == 'ACTIVE'"> ... </when><when test="state == 'INACTIVE'"> ... </when><otherwise> ... </otherwise>
          </choose>
        • <trim> / <where> / <set>

          • <where>: 智能处理WHERE子句。它会自动移除其内部片段开头多余的ANDOR,并且只在至少有一个子条件成立时才插入WHERE关键字。避免WHERE后直接跟AND的错误。

          • <set>: 智能处理UPDATE语句中的SET子句。它会自动移除结尾的逗号,,并且只在至少有一个子条件成立时才插入SET关键字

          • <trim>: 更通用的字符串修剪标签。通过prefix(添加前缀)、suffix(添加后缀)、prefixOverrides(移除前缀中匹配的字符串)、suffixOverrides(移除后缀中匹配的字符串)属性实现更灵活的修剪。<where><set>是其特定场景的便捷实现。

        • <foreach> 遍历集合(如List, Set, Array, Map),常用于IN条件或批量操作。

          xml

          <foreach item="item" index="index" collection="list"open="(" separator="," close=")">#{item}
          </foreach>
        • <bind> 创建一个变量并将其绑定到当前上下文,常用于模糊查询拼接或复杂表达式复用。

          xml

          <bind name="pattern" value="'%' + name + '%'" />
          AND username LIKE #{pattern}
      • 语法 (OGNL 表达式): 在test属性中编写逻辑判断表达式。常用:

        • 判断对象/属性是否为nullparam != nullname == null

        • 判断字符串是否为空/非空: name != null and name != '' (或使用@org.apache.commons.lang3.StringUtils@isNotBlank(name) 如果导入了库)

        • 判断集合/数组是否为空/非空: list != null and !list.isEmpty()array.length > 0

        • 比较操作符: ==!=<><=>=

        • 逻辑操作符: and (或 &&), or (或 ||), not (或 !)

        • 调用JavaBean方法: user.isAdmin()

  7. Q: Mybatis都有哪些Executor执行器?它们之间的区别是什么?

    • A: MyBatis有三种基本的Executor执行器:

      1. SimpleExecutor (简单执行器,默认):

        • 行为: 每次执行updatequery操作时,都会创建一个新的PreparedStatement对象

        • 特点: 执行完SQL后,立即关闭PreparedStatement对象(以及对应的ResultSet)。

        • 优点: 实现简单。

        • 缺点: 没有Statement复用,效率较低

      2. ReuseExecutor (重用执行器):

        • 行为: 重用预处理语句(PreparedStatement)。在执行SQL时,会先根据SQL语句本身作为Key在一个Map缓存中查找是否存在可用的PreparedStatement。如果存在则直接使用;如果不存在,则创建新的PreparedStatement并放入缓存。

        • 特点: 同一个SQL语句(严格匹配)在同一个SqlSession内只会预编译一次

        • 优点: 减少了数据库对相同SQL的预编译开销,提高了效率(尤其对于频繁执行相同SQL的场景)。

        • 缺点: 缓存作用域是SqlSession级别。缓存的是PreparedStatement,不是Connection

      3. BatchExecutor (批量执行器):

        • 行为: 专门用于批量更新操作 (insertupdatedelete)。

        • 特点: 将所有更新操作都添加到一个批处理队列中。等待显式调用commit()flushStatements()或执行一个查询操作时,才一次性将所有队列中的更新操作发送到数据库执行

        • 优点: 大幅提升批量操作的性能,减少网络IO次数。

        • 缺点: 不适用于查询(select)。使用时需要注意事务管理和内存占用(队列大小)。在SqlSession关闭或commit时,未执行的批处理会被丢弃。

      • CachingExecutor (缓存执行器): 严格来说这不是一个“基本”执行器,而是一个装饰器。它包裹在上述三种执行器之上,提供二级缓存功能。先查询二级缓存,缓存未命中再委托给底层的Executor去数据库查询,并将查询结果存入二级缓存。

      • 区别总结:

        执行器核心行为适用场景主要优点主要缺点
        SimpleExecutor每次执行创建新Statement,用完即关通用简单效率低 (无复用)
        ReuseExecutor复用相同SQL的PreparedStatement频繁执行相同SQL减少预编译开销作用域仅限SqlSession
        BatchExecutor批量收集更新操作,最后一次性执行批量插入/更新/删除大幅提升批量性能不适用查询;需注意提交和内存
        CachingExecutor装饰器,提供二级缓存需要利用二级缓存减少数据库访问需要管理缓存一致性
  8. Q: 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

    • A:

      • 半自动ORM: MyBatis被称为半自动ORM映射工具,核心在于它只自动化了SQL执行和结果集映射到对象的过程。开发者需要手动编写具体的SQL语句(或通过Mapper接口方法+注解定义)。开发者对SQL拥有完全的掌控权,可以精细地优化SQL性能,处理复杂查询和数据库特性。

      • 全自动ORM (如 Hibernate, JPA): 全自动ORM框架的目标是让开发者完全面向对象编程不需要手动编写SQL。框架根据定义的实体类(Entity)和映射关系(Annotations/XML),在运行时自动生成所需的SQL语句(CRUD操作、关联查询等)。开发者操作的是对象,框架负责对象与数据库表记录的转换和SQL生成。

      • 核心区别:

        特性MyBatis (半自动)Hibernate/JPA (全自动)
        SQL控制开发者手动编写、控制SQL框架自动生成SQL
        灵活性极高,可编写任意复杂、优化SQL受限,依赖于框架生成的SQL
        学习曲线相对较低,需熟悉SQL相对较高,需理解ORM抽象和HQL/JQL
        性能调优直接优化SQL,调优更直接需理解框架行为、缓存、抓取策略等
        数据库移植性较差,SQL可能依赖特定数据库语法较好,框架负责方言转换
        开发效率简单CRUD需写SQL,效率可能稍低简单CRUD效率高,复杂查询需HQL
        适用场景需要精细SQL控制、复杂查询、高性能优化、遗留数据库快速开发、数据库无关性强、对象模型复杂
  9. Q: 简单介绍下你对Mybatis的理解?

    • A: MyBatis是一款优秀的半自动化持久层框架。它通过XML配置文件注解将SQL语句与Java对象(POJO)的映射关系解耦。MyBatis的核心价值在于它封装了JDBC底层的繁琐操作(如手动创建/关闭ConnectionStatementResultSet,手动设置参数,手动处理结果集映射),让开发者只需关注SQL本身和业务对象。它提供了强大的特性:

      • 动态SQL: 灵活构建复杂SQL。

      • 灵活的映射: 支持自动映射(resultType)和高度自定义映射(resultMap),处理复杂对象关系。

      • 插件机制: 可扩展框架行为。

      • 缓存: 提供一级缓存(SqlSession级别)和二级缓存(Namespace/Mapper级别)提升性能。

      • 与Spring集成: 无缝整合Spring IoC和事务管理。
        平衡了SQL控制力与开发效率,尤其适合需要对SQL进行深度优化和控制的场景,是Java持久层框架中的重要选择。

三、Spring Core (IoC, Bean, AOP)

  1. Q: 介绍一下Spring的事物管理?

    • A: Spring提供了声明式编程式两种事务管理方式,旨在简化事务管理代码,提供一致的编程模型,并支持多种事务API(JDBC, JPA, Hibernate, JTA等)。

      • 核心接口: PlatformTransactionManager (平台事务管理器) 是核心抽象。针对不同持久化技术有具体实现(如DataSourceTransactionManager用于JDBC/MyBatis, HibernateTransactionManagerJpaTransactionManagerJtaTransactionManager)。

      • 声明式事务 (主流): 基于AOP (面向切面编程) 实现。开发者通过配置(XML或@Transactional注解)来定义事务的属性(传播行为、隔离级别、超时、只读、回滚规则),而无需在业务代码中编写事务管理代码(如begincommitrollback)。Spring容器在运行时为配置了事务属性的Bean创建代理对象,在目标方法执行前后加入事务管理的逻辑。优点: 非侵入性,业务代码清晰,配置灵活。

      • 编程式事务: 在代码中显式调用Spring提供的事务管理API(如TransactionTemplate或直接使用PlatformTransactionManager)来控制事务边界(开始、提交、回滚)。优点: 更精细的控制。缺点: 侵入性强,代码冗余,通常只在需要非常精细控制或声明式无法满足的复杂场景中使用。

      • 关键配置属性 (@Transactional):

        • 传播行为 (Propagation): 定义事务方法在调用另一个事务方法时的行为(7种,如REQUIRED-默认,存在则加入,不存在则新建;REQUIRES_NEW-总是新建事务;NESTED-嵌套事务等)。

        • 隔离级别 (Isolation): 定义事务的隔离程度(解决脏读、不可重复读、幻读问题),如DEFAULT(使用数据库默认)、READ_COMMITTEDREPEATABLE_READSERIALIZABLE

        • 超时 (timeout): 事务超时时间(秒),超过自动回滚。

        • 只读 (readOnly): 提示数据库优化(设置为true)。

        • 回滚规则 (rollbackFor / noRollbackFor): 指定哪些异常触发回滚或哪些异常不触发回滚。

      • 优势: 统一API、支持声明式(减少样板代码)、灵活配置传播隔离等、与Spring生态无缝集成。

  2. Q: Bean 工厂和 Application contexts 有什么区别?

    • A: BeanFactoryApplicationContext都是Spring IoC容器的核心接口,用于管理Bean的生命周期、依赖注入。ApplicationContextBeanFactory的一个功能更强大的子接口

      • BeanFactory (基础容器):

        • 提供最基础的IoC功能:Bean的实例化、配置、组装、生命周期管理(调用初始化init和销毁destroy方法)。

        • 采用懒加载 (Lazy-loading) 策略:Bean在第一次被请求时才创建和初始化。

        • 功能相对有限,不支持AOP、事件、资源访问、国际化等企业级特性。

        • 适用于资源受限的环境(如移动设备、Applet)。

      • ApplicationContext (高级容器,主流):

        • 继承了BeanFactory的所有功能,是它的超集

        • 提供更丰富的企业级服务

          • 继承MessageSource,支持国际化 (i18n)。

          • 继承ResourceLoader,提供更便捷的资源文件访问方式 (如classpath:file:url:)。

          • 支持事件发布/订阅机制 (ApplicationEventPublisher)。

          • 集成AOP功能。

          • 更方便的访问特定环境信息 (Environment)。

          • 自动注册BeanPostProcessorBeanFactoryPostProcessor

        • 默认采用预实例化 (Eager-loading) 策略:容器启动时,单例作用域(Singleton)的Bean默认会被立即创建和初始化(除非显式配置为懒加载)。这有助于在应用启动时尽早发现配置错误。

        • 是Spring应用的主要入口点,代表完整的应用上下文。

      • 总结: ApplicationContextBeanFactory的基础上增加了大量面向应用框架的特性,是绝大多数Spring应用(尤其是Web应用)使用的容器。BeanFactory是更底层、更轻量的容器。通常直接使用ApplicationContext的实现类(如ClassPathXmlApplicationContextAnnotationConfigApplicationContextFileSystemXmlApplicationContextWebApplicationContext)。

  3. Q: 解释Spring支持的几种bean的作用域?

    • A: Spring Bean的作用域定义了Bean实例的生命周期和在容器中的可见范围。常用作用域如下:

      作用域描述适用场景
      singleton (默认)每个Spring IoC容器中,该Bean定义只存在一个共享的实例。所有对该Bean的依赖引用都指向同一个对象。无状态的服务、工具类、DAO层组件、配置类。
      prototype每次请求(如通过applicationContext.getBean()或注入点)该Bean时,容器都会创建一个新的实例有状态的Bean(如用户会话、购物车),需要每次使用时都是新实例的场景。
      request每个HTTP请求的生命周期内,该Bean定义只存在一个实例。仅适用于Web应用存储与单个HTTP请求相关的数据(如表单绑定对象、请求处理器)。
      session每个用户HTTP Session的生命周期内,该Bean定义只存在一个实例。仅适用于Web应用存储用户会话状态(如登录用户信息、用户偏好设置)。
      application整个Web应用(ServletContext)的生命周期内,该Bean定义只存在一个实例。作用域比singleton更广,是跨多个Servlet容器的singleton仅适用于Web应用应用级别的缓存、共享资源(类似ServletContext属性)。
      websocket每个WebSocket会话的生命周期内,该Bean定义只存在一个实例。仅适用于WebSocket应用存储与单个WebSocket会话相关的状态。
      • 注意: 后四种作用域(requestsessionapplicationwebsocket)都依赖于WebApplicationContext(如Spring MVC使用的容器)。标准ApplicationContext只支持singletonprototype

  4. Q: 什么是bean的自动装配?

    • A: Bean的自动装配 (Autowiring) 是Spring容器提供的一种机制,用于自动解析注入一个Bean所依赖的其他Bean,而无需开发者在配置文件中(XML或Java Config)显式地通过<property><constructor-arg>标签(或@Autowired注解对应的配置方式)指定依赖关系。Spring容器会根据类型匹配 (byType) 或 名称匹配 (byName) 等规则,在上下文中查找符合条件的Bean并自动注入。

    • 主要方式 (XML配置中 <bean> 的 autowire 属性):

      • no: (默认) 不自动装配,必须手动指定依赖。

      • byName: 根据属性名在容器中查找同名的Bean进行注入。

      • byType: 根据属性类型在容器中查找类型匹配的Bean进行注入。如果找到多个同类型Bean,会抛出异常。需要确保该类型只有一个Bean定义。

      • constructor: 类似于byType,但是应用于构造器参数。如果容器中有多个与构造器参数类型匹配的Bean,会尝试根据参数名匹配Bean名,否则报错。

    • 注解驱动 (主流): 使用@Autowired注解(或@Inject(JSR-330), @Resource(JSR-250))标注在字段、Setter方法或构造器上,Spring会自动查找匹配的Bean进行注入。@Autowired默认按类型 (byType) 装配。如果需要按名称,可以结合@Qualifier("beanName")注解使用。@Resource默认按名称 (byName) 装配,找不到再按类型。

    • 优点: 减少显式配置,简化XML或Java Config,使代码更简洁。

    • 缺点: 过度使用可能导致配置不够清晰,依赖关系不直观,且自动装配失败(如byType找到多个候选者)可能带来运行时错误。需谨慎使用,特别是在大型项目中。显式配置通常更可控。

  5. Q: 什么是基于Java的Spring注解配置? 给一些注解的例子?

    • A: 基于Java的Spring注解配置是一种完全替代传统XML配置文件的Spring容器配置方式。开发者通过编写Java类(使用@Configuration注解标记),并在其中使用各种Spring注解(如@Bean@ComponentScan@Import@PropertySource等)来定义Bean、Bean之间的依赖关系、组件扫描路径、属性源、导入其他配置类等。

    • 核心注解举例:

      • @Configuration 标记在一个类上,表明该类是一个Spring配置类,其作用类似于一个XML配置文件。Spring容器会处理其中定义的@Bean方法。

      • @Bean 标记在@Configuration类中的方法上。该方法负责创建、配置并返回一个需要由Spring IoC容器管理的对象。方法名默认作为Bean的名称,也可以通过name属性指定。

        java

        @Configuration
        public class AppConfig {@Beanpublic DataSource dataSource() { ... } // Bean名 'dataSource'@Bean(name = "myService")public MyService myService() { // Bean名 'myService'return new MyServiceImpl(dataSource());}
        }
      • @ComponentScan 标记在@Configuration类上,指示Spring去哪些包路径下扫描被@Component及其衍生注解(@Service@Repository@Controller)标记的类,并自动将它们注册为Spring Bean。 可指定basePackagesbasePackageClasses

        java

        @Configuration
        @ComponentScan("com.example.service") // 扫描com.example.service包
        @ComponentScan(basePackageClasses = {MyService.class}) // 扫描MyService类所在的包
        public class AppConfig { ... }
      • @Import 标记在@Configuration类上,用于导入其他配置类(可以是@Configuration类或实现了ImportSelector/ImportBeanDefinitionRegistrar的类)。允许模块化配置。

        java

        @Configuration
        @Import({DatabaseConfig.class, SecurityConfig.class})
        public class AppConfig { ... }
      • @PropertySource 标记在@Configuration类上,用于加载外部的属性文件(如.properties)到Spring的Environment。然后可以通过@Value("${prop.key}")注入或Environment.getProperty("key")访问。

        java

        @Configuration
        @PropertySource("classpath:app.properties")
        public class AppConfig {@Value("${jdbc.url}")private String url;// 或者通过Environment@Autowiredprivate Environment env;
        }
      • @Profile 标记在@Configuration类或@Bean方法上,只有当指定的Profile被激活时,该配置类或Bean定义才会生效。 用于环境隔离(如dev, test, prod)。

        java

        @Configuration
        @Profile("development")
        public class DevConfig { ... }
      • @Lazy 标记在@Component类或@Bean方法上,指示该Bean应延迟初始化(在第一次被请求时才创建),而不是在容器启动时立即创建。适用于开销大的Bean或不常用的Bean。

      • @Scope 标记在@Component类或@Bean方法上,显式指定Bean的作用域(如@Scope("prototype")@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE))。

    • 优点: 类型安全(编译器检查)、重构友好、配置更集中(在代码中)、减少XML配置的繁琐、支持条件化配置(如@Profile@Conditional)。

  6. Q: Spring中@Autowired和@Resource之间区别是什么?

    • A: @Autowired (Spring特有) 和 @Resource (JSR-250标准) 都是用于依赖注入的注解,主要区别在于注入规则来源

      特性@Autowired (Spring)@Resource (JSR-250)
      所属规范Spring框架 特有Java EE (JSR-250) 标准注解
      默认注入规则按类型 (byType) 进行装配。按名称 (byName) 进行装配。
      处理者AutowiredAnnotationBeanPostProcessor (Spring)CommonAnnotationBeanPostProcessor (Spring处理JSR注解)
      指定名称需要结合 @Qualifier("beanName") 注解直接使用 name 属性 (@Resource(name = "myBean"))
      处理找不到的情况默认情况下,如果找不到匹配的Bean,会抛出NoSuchBeanDefinitionException。可通过设置required=false允许为null (@Autowired(required = false))。如果未指定name且按名称找不到,则回退到按类型 (byType) 查找。如果按类型也找不到或不唯一,则抛出异常。
      适用范围可标注在构造器、字段、Setter方法、普通方法上。可标注在字段、Setter方法上。不能标注在构造器或普通方法上。
      • 简单总结: 优先使用@Autowired,它是Spring生态首选,功能更灵活(支持构造器注入)。当需要明确按名称注入时,使用@Resource(name="xxx")更直接。如果项目需要兼容非Spring容器(如其他JSR-250实现容器),@Resource是更好的选择。

  7. Q: 在Spring AOP 中,连接点和切入点的区别是什么?

    • A: 这是AOP中的两个核心概念:

      • 连接点 (Join Point): 指在程序执行过程中的一个具体点,这个点可以被AOP框架拦截并在其上应用通知(Advice)。在Spring AOP中,连接点特指方法的执行(即当某个方法被调用时)。例如:UserService.saveUser()方法的调用就是一个连接点。

      • 切入点 (Pointcut): 是一个谓词(表达式),用于匹配/筛选哪些连接点(Join Point)会被通知(Advice)所作用。它定义了通知应该应用在哪些连接点上。切入点表达式描述了“在什么地方执行通知”。例如:一个切入点表达式execution(* com.example.service.*.*(..))匹配了com.example.service包下所有类的所有方法的执行。只有被切入点匹配到的连接点,才会被关联的Advice拦截处理。

      • 关键区别:

        • 连接点是程序中客观存在的点(方法执行)。

        • 切入点是开发者定义的规则/条件,用来选择特定的连接点。

        • 一个切入点可以匹配多个连接点。

        • 通知 (Advice) 是与切入点关联的,它定义了在匹配到的连接点上做什么以及何时做

  8. Q: AOP作用是什么,底层如何实现?在哪些地方会用到?分别简述切面,切入点和通知?

    • A:

      • 作用 (Why AOP?):

        1. 代码复用与模块化: 将散布在应用多处的横切关注点(Cross-Cutting Concerns)代码(如日志、事务管理、安全、性能监控、异常处理等)抽取出来,封装到独立的模块(切面)中。一处定义,多处使用

        2. 业务逻辑纯净: 业务模块(核心关注点)的代码不再混杂横切关注点代码,更清晰、更聚焦核心业务

        3. 提高可维护性: 当需要修改横切关注点逻辑(如更改日志格式、事务策略)时,只需修改切面,无需在所有相关业务代码中搜索修改。

        4. 提高可扩展性: 可以方便地添加或移除横切功能。

      • 底层实现 (How? - Spring AOP): Spring AOP主要使用动态代理技术实现。

        1. 代理创建: 当Spring容器创建Bean时,如果发现该Bean匹配了某个切入点(即有通知需要应用到它),容器会为目标Bean创建一个代理对象

          • 如果目标对象实现了接口,默认使用JDK动态代理(基于接口)。

          • 如果目标对象没有实现接口,则使用CGLIB库生成目标类的子类作为代理(基于类)。

        2. 代理拦截: 当客户端调用代理对象的方法时:

          • 代理对象会检查该方法是否匹配配置的切入点

          • 如果匹配,则执行与该切入点关联的通知链(Before, After, Around等)。

          • 在通知链中,最终会通过反射调用目标对象(原始Bean)的实际方法(在Around通知中由ProceedingJoinPoint.proceed()触发)。

      • 应用场景 (Where?):

        • 日志记录: 统一记录方法入参、出参、执行时间、异常等。

        • 事务管理: 声明式事务的核心实现(@Transactional)。

        • 安全控制: 方法调用前的权限检查(如@PreAuthorize)。

        • 性能监控: 统计方法执行耗时。

        • 异常处理: 统一异常捕获和转换。

        • 缓存: 方法结果缓存(@Cacheable)。

        • 数据校验: 方法执行前的参数校验。

      • 核心概念 (What?):

        1. 切面 (Aspect): 横切关注点的模块化体现。它封装了通知和切入点。在Spring AOP中,切面通常是一个用@Aspect注解标记的Java类。它包含多个通知和切入点定义。

        2. 切入点 (Pointcut): 一个表达式,用于匹配连接点(在Spring AOP中就是方法执行)。它定义了“在哪里执行通知”。例如:@Pointcut("execution(* transfer(..))")定义了一个匹配所有名为transfer的方法执行的切入点。

        3. 通知 (Advice): 切面在特定的连接点(由切入点匹配)上执行的动作。它定义了“做什么以及何时做”。Spring AOP支持的通知类型:

          • Before: 在目标方法执行之前执行通知。使用@Before注解。

          • After returning: 在目标方法成功执行完成(正常返回)之后执行通知。使用@AfterReturning注解。

          • After throwing: 在目标方法抛出异常退出之后执行通知。使用@AfterThrowing注解。

          • After (finally): 在目标方法执行结束之后(无论正常返回还是异常退出)执行通知(类似finally块)。使用@After注解。

          • Around: 环绕目标方法的执行。这是功能最强大的通知类型,可以在目标方法执行前、后执行自定义行为,并控制是否执行目标方法、何时执行、以及如何处理返回值或异常。使用@Around注解。它接收一个ProceedingJoinPoint参数,通过调用其proceed()方法来执行目标方法。

四、SSM整合与对比

  1. Q: SSM优缺点、使用场景?

    • A:

      • Spring Framework:

        • 优点:

          • 强大的IoC/DI容器: 解耦组件依赖,管理对象生命周期,提高可测试性和可维护性。

          • AOP支持: 模块化横切关注点(事务、日志、安全等)。

          • 声明式事务管理: 简化数据库事务操作,提高开发效率。

          • 强大的整合能力: 提供模板类简化各种技术的使用(JDBC, JMS, JPA等)。

          • 丰富的生态系统: Spring Boot, Spring Cloud, Spring Security, Spring Data等。

          • 高度模块化: 可按需引入模块。

        • 缺点:

          • 学习曲线: 概念众多(IoC, DI, AOP, Bean生命周期等),对新手有一定门槛。

          • 配置复杂性: 虽然Spring Boot极大简化了配置,但深入理解和定制仍需处理较复杂的配置(尤其在大型项目)。

          • 运行时性能开销: AOP、动态代理等机制会带来轻微性能损耗(通常可忽略)。

        • 使用场景: 几乎适用于任何规模的Java/Java EE应用开发,是现代Java开发的基础框架。特别适合需要松耦合、可测试、可扩展、需要整合多种技术的企业级应用。

      • Spring MVC:

        • 优点:

          • 清晰的MVC分层: 分离关注点,代码结构清晰。

          • 灵活强大的配置: 注解驱动,支持RESTful,视图技术灵活。

          • 与Spring无缝集成: 享受Spring IoC、AOP等所有特性。

          • 高性能: 相比Struts2等更轻量高效。

          • 强大的数据绑定和验证: 简化请求参数处理。

          • 强大的测试支持: 易于进行Web层单元测试和集成测试。

        • 缺点:

          • 配置相对较多: 虽然注解简化了很多,但完全理解DispatcherServlet、HandlerMapping等配置仍需时间(Spring Boot极大缓解)。

          • 原生对高并发IO支持有限: 传统Servlet模型是阻塞IO。应对超高并发需结合异步(DeferredResult/Callable)或转向响应式(WebFlux)。

        • 使用场景: 构建基于Servlet API的Web应用程序,特别是需要RESTful API、需要与Spring深度集成、追求性能的Web项目。

      • MyBatis:

        • 优点:

          • SQL完全可控: 开发者直接编写和优化SQL,性能调优直接有效。

          • 灵活的映射: resultMap功能强大,能处理复杂对象关系映射。

          • 动态SQL: 灵活构建复杂查询条件。

          • 轻量级: 学习曲线相对平缓,依赖少。

          • 与Spring集成好: 通过SqlSessionFactoryBeanMapperScannerConfigurer等轻松整合。

          • 性能优化灵活: 一级/二级缓存、插件机制、执行器选择。

        • 缺点:

          • 需要手动编写SQL: 简单CRUD也需写SQL,相比JPA开发效率略低。

          • 数据库移植性差: SQL依赖特定数据库方言。

          • 关联查询配置相对复杂: 尤其是深层次的复杂关联。

          • XML依赖 (可选但常用): 虽然支持注解,但复杂SQL和映射通常还是用XML。

        • 使用场景:

          • 需要精细控制和优化SQL性能的项目(如金融、交易系统)。

          • 遗留系统维护或数据库Schema复杂、SQL优化空间大的系统。

          • 开发者更熟悉SQL,或者团队有DBA需要介入SQL优化。

          • 中小型项目,或者大型项目中需要直接操作复杂SQL的部分模块。

          • 数据库移植性要求不高的项目。

      • SSM组合使用场景: SSM组合特别适合于需要平衡SQL控制力、Web开发效率、框架灵活性和成熟度的中大型企业级Java Web应用开发。是传统Java EE三层架构(Web层-Spring MVC, Service层-Spring, Dao层-MyBatis)的经典实现。

五、整合 Hibernate (可选,但题目包含)

  1. Q: 使用Spring通过什么方式访问Hibernate?

    • A: Spring 提供了多种方式来整合和访问 Hibernate:

      1. 原生 Hibernate API (使用 SessionFactory 和 Session):

        • 配置: 在Spring配置中定义一个LocalSessionFactoryBean,用于创建Hibernate的SessionFactory。它需要配置数据源、实体类扫描路径、Hibernate属性(如方言hibernate.dialect)。

        • 访问: 在DAO层,可以通过HibernateTemplate(Spring提供的模板类,简化Session操作,处理异常和资源管理)或者直接注入SessionFactory,然后通过SessionFactory.getCurrentSession()(通常绑定到Spring事务)或openSession()获取Session进行数据库操作。HibernateTemplate在早期流行,现在更推荐直接使用SessionFactory配合Spring的声明式事务。

        • 特点: 相对底层,控制力强。

      2. 基于 JPA 标准 (使用 EntityManager):

        • 配置: 在Spring配置中定义一个LocalContainerEntityManagerFactoryBean,它负责创建JPA标准的EntityManagerFactory,并指定Hibernate作为其底层JPA实现提供者(HibernateJpaVendorAdapter)。同样需要配置数据源、实体扫描、JPA/Hibernate属性。

        • 访问: 在DAO层,可以通过@PersistenceContext注解注入EntityManager。通过EntityManager进行符合JPA标准的持久化操作(persist()merge()find()createQuery()等)。

        • 特点: 使用标准JPA API,代码更具移植性(理论上可切换JPA实现),Spring对JPA支持完善(如@Transactional)。这是目前更主流的方式。

      3. Spring Data JPA:

        • 配置: 继承方式2(配置LocalContainerEntityManagerFactoryBean),然后定义一个继承JpaRepository<T, ID>的接口。

        • 访问: Spring Data JPA会自动为这个接口生成实现。开发者只需定义接口,就可以直接使用常见的CRUD方法(save()findById()findAll()delete()等)以及通过方法名约定或@Query注解定义查询,几乎无需编写实现代码

        • 特点: 极大简化DAO层开发,减少样板代码。非常适合标准CRUD和简单查询场景。复杂查询仍需结合@Query或JPA Criteria API。底层依然是Hibernate作为JPA提供者。

      • 事务管理: 无论哪种方式,都推荐使用Spring的声明式事务管理 (@Transactional),并配置HibernateTransactionManager (对于方式1) 或 JpaTransactionManager (对于方式2和3)。

  2. Q: 如何通过HibernateDaoSupport将Spring和Hibernate结合起来?

    • A: HibernateDaoSupport是Spring提供的一个便利的DAO基类(现在已不常用,更推荐直接注入SessionFactory或使用Spring Data JPA),用于简化整合。步骤如下:

      1. 配置 SessionFactory: 在Spring的ApplicationContext配置文件中,定义一个LocalSessionFactoryBean Bean,配置数据源、映射资源/实体类、Hibernate属性等。

      2. 创建 DAO 类: 编写具体的DAO实现类,继承 org.springframework.orm.hibernate5.support.HibernateDaoSupport (注意版本,如hibernate3/4/5)。

      3. 注入 SessionFactory: 在DAO类中,需要通过Setter注入构造器注入的方式,将配置好的SessionFactory Bean注入。HibernateDaoSupport类内部有一个setSessionFactory(SessionFactory sessionFactory)方法。通常通过Spring依赖注入完成:

        • XML: <bean id="myDao" class="com.example.dao.MyDaoImpl"><property name="sessionFactory" ref="sessionFactoryBean"/></bean>

        • 注解: 在DAO类上使用@Repository,并添加一个@Autowired的Setter方法或字段(但基类要求Setter)。

      4. 访问数据库: 在DAO方法中,可以通过getHibernateTemplate()方法获取HibernateTemplate实例,然后调用其提供的方法进行数据库操作,如:

        • getHibernateTemplate().save(Object entity)

        • getHibernateTemplate().get(Class entityClass, Serializable id)

        • getHibernateTemplate().find(String queryString, Object... values)

        • getHibernateTemplate().update(Object entity)

        • getHibernateTemplate().delete(Object entity)
          HibernateTemplate内部负责处理Session的获取/释放、异常转换(将Hibernate专有异常转换为Spring的DataAccessException层次结构)、事务同步等。

      5. 事务管理: 在Service层使用Spring的声明式事务管理 (@Transactional),并配置HibernateTransactionManager

      • 注意: HibernateTemplateHibernateDaoSupport在较新的Spring/Hibernate版本中已逐渐被视为过时,因为它们:

        • 引入了额外的抽象层。

        • 限制了直接使用原生Session API的灵活性。

        • 现代实践更倾向于直接注入SessionFactory(或EntityManager)并使用@Transactional管理事务

http://www.dtcms.com/a/313423.html

相关文章:

  • 02.Redis 安装
  • MPLS 静态LSP
  • TV电视版软件集合分享
  • 深入理解Java并发编程:原理、实战与最佳实践
  • Redis 7 中的 Set 和 Zset 使用
  • 基于transformer的目标检测——匈牙利匹配算法
  • 深入解析HashMap:原理与性能优化
  • Vim编辑器详解:从入门到高效使用
  • 从零开始的CAD|CAE开发: LBM源码实现分享
  • 编程语言分类
  • JAVAEE--5.多线程之常见的锁策略
  • AI Competitor Intelligence Agent Team
  • 【openlayers框架学习】七:绘制线要素以及点击画线功能
  • 力扣热题100----------141.环形链表
  • 基于BiLSTM+CRF实现NER
  • 【机器人】VLN-R1 微调 | 增强训练 | 连续导航
  • Web3合约ABI,合约地址生成部署调用及创建,连接钱包,基础交易流程
  • ARPO:让LLM智能体更高效探索
  • 【Linux网络编程基础--socket地址API】
  • 多 4G 通讯模组共存时的干扰问题深度解析与解决方案
  • leecode-每日一题-2106. 摘水果
  • vmfusion启动centos6.10 一直卡到call 169.254.169.254
  • 全面解析 BGE Embedding 模型:训练方式、模型系列与实战用法
  • Redis——常用指令汇总指南(三)(哈希类型)
  • 编写xsync集群分发脚本(保姆级别)
  • Redis 数据同步机制
  • 【Linux】Makefile Cmake—基操
  • [特殊字符]字节Get!免费进楼攻略速存[特殊字符]
  • LWIP从FreeRTOS到uC/OS-III的适配性改动
  • linux 扩展未分配的磁盘空间到home下