SSM框架中关于Spring MVC的技术问题

发布于:2025-07-24 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、SpringMVC的执行流程

        Spring MVC是Spring框架的一个模块,是一个基于Java的实现了MVC设计模式的轻量级Web框架。它通过一套注解和接口,让简单的Java类成为处理请求的控制器,无需实现任何接口,同时支持REST风格的编程。

SpringMVC 的执行流程是其核心工作原理:

1.视图阶段(JSP)

  1. 用户发送请求:客户端(浏览器等)发送 HTTP 请求到前端控制器(DispatcherServlet)。

  2. 前端控制器接收请求:DispatcherServlet 作为 SpringMVC 的核心,接收所有请求并进行统一处理。

  3. 处理器映射器查找处理器:DispatcherServlet 调用 HandlerMapping(处理器映射器),根据请求 URL 查找对应的 Handler(处理器,如 Controller 中的方法)。

  4. 返回处理器执行链:HandlerMapping 返回一个 HandlerExecutionChain 对象,包含找到的 Handler 和对应的拦截器(Interceptor)。

  5. 处理器适配器调用处理器:DispatcherServlet 调用 HandlerAdapter(处理器适配器),由它负责调用具体的 Handler 执行处理逻辑。

  6. 处理器执行处理逻辑:Handler(通常是 Controller 中的方法)执行具体的业务处理,处理完成后返回一个 ModelAndView 对象(包含模型数据和视图名称)。

  7. 处理器适配器返回结果:HandlerAdapter 将 Handler 执行后的 ModelAndView 返回给 DispatcherServlet。

  8. 视图解析器解析视图:DispatcherServlet 调用 ViewResolver(视图解析器),根据 ModelAndView 中的视图名称解析出具体的 View(视图)对象。

  9. 视图渲染:View 对象结合 Model 中的数据进行渲染,生成最终的响应内容(如 HTML)。

  10. 返回响应:DispatcherServlet 将渲染后的结果返回给客户端,完成一次请求的处理。

        整个流程中,DispatcherServlet 负责协调各个组件的工作,降低了组件之间的耦合度,体现了 SpringMVC 的设计优势。

2.前后端分离阶段(接口开发,异步请求)

  1. 用户发送请求:客户端(浏览器等)发送 HTTP 请求到前端控制器(DispatcherServlet)。

  2. 前端控制器接收请求:DispatcherServlet 作为 SpringMVC 的核心,接收所有请求并进行统一处理。

  3. 处理器映射器查找处理器:DispatcherServlet 调用 HandlerMapping(处理器映射器),根据请求 URL 查找对应的 Handler(处理器,如 Controller 中的方法)。

  4. 返回处理器执行链:HandlerMapping 返回一个 HandlerExecutionChain 对象,包含找到的 Handler 和对应的拦截器(Interceptor)。

  5. 处理器适配器调用处理器:DispatcherServlet 调用 HandlerAdapter(处理器适配器),由它负责调用具体的 Handler 执行处理逻辑。

  6. 处理器执行处理逻辑:Handler(通常是 Controller 中的方法)执行具体的业务处理。

  7. 返回响应:方法上添加了@ResponseBody注解,通过HttpMessageConverter来返回结果转换为JSON并响应。

二、Springboot自动配置原理

        Spring Boot 的自动配置是其核心特性之一,它通过约定优于配置的思想,简化了 Spring 应用的搭建和开发过程。

        在Spring Boot启动类上有一个@SpringBootApplication注解,包含了以下三个注解的功能:

  • @SpringBootConfiguration:标识该类为一个配置类。

  • @EnableAutoConfiguration:启用自动配置功能。

  • @ComponentScan:扫描并注册组件。

1.@EnableAutoConfiguration 注解

        @EnableAutoConfiguration 是自动配置的核心注解,它通过 @Import(AutoConfigurationImportSelector.class) 导入了 AutoConfigurationImportSelector 类。这个类负责选择和加载所有符合条件的自动配置类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

        AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,这个方法经过层层调用,最终会读取META-INF 目录下的 后缀名 为imports的文件(springboot2.7以前的版本,读取的是spring.factories文件;2.7~3.0之间的版本读取的是spring.factories或.imports;3.0以后的版本是.import文件)。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
        ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

        读取到全类名了之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中。

2.自定义start

        在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot 的 starter。

        实现一个自定义的 Spring Boot Starter,我们需要创建一个能够被 Spring Boot 自动配置的模块。下面将实现一个简单的 "hello-service" starter,它提供一个问候服务。

2.1 创建start

创建一个 Maven 项目,结构如下:

HelloService:

package com.hl.service;

/**
 * 问候服务类,提供基础的问候功能
 */
public class HelloService {

    private String prefix;
    private String suffix;

    public HelloService(String prefix, String suffix) {
        this.prefix = prefix;
        this.suffix = suffix;
    }

    /**
     * 生成问候语
     */
    public String sayHello(String name) {
        return prefix + name + suffix;
    }

    // getter和setter方法
    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

HelloProperties:

package com.hl.autoconfigure;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 配置属性类,用于绑定application.properties中的配置
 */
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {

    // 默认前缀
    private String prefix = "Hello, ";

    // 默认后缀
    private String suffix = "!";

    // getter和setter方法
    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

HelloAutoConfiguration:

package com.hl.autoconfigure;

import com.hl.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自动配置类,负责创建和配置HelloService实例
 */
@Configuration
@ConditionalOnClass(HelloService.class) // 当类路径下存在HelloService时才生效
@EnableConfigurationProperties(HelloProperties.class) // 启用配置属性
public class HelloAutoConfiguration {

    private final HelloProperties helloProperties;

    // 注入配置属性
    public HelloAutoConfiguration(HelloProperties helloProperties) {
        this.helloProperties = helloProperties;
    }

    // 注册HelloService Bean
    @Bean
    @ConditionalOnMissingBean // 当容器中没有HelloService Bean时才创建
    public HelloService helloService() {
        return new HelloService(
                helloProperties.getPrefix(),
                helloProperties.getSuffix()
        );
    }
}

在spring.factories中注册自动配置类:

# 注册自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.hl.autoconfigure.HelloAutoConfiguration

2.2 使用自定义 Starter

首先将上面的 starter 项目安装到本地 Maven 仓库:

mvn clean install

在需要使用的项目中添加依赖:

<!-- 自定义start  -->
        <dependency>
            <groupId>com.HL</groupId>
            <artifactId>hello-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

在 application.yml中配置:

hello:
  prefix: Hi,
  suffix: Welcome!

在代码中使用:

@Tag(name = "hello接口")
@RestController
@RequestMapping("/hello")
public class HelloController {

    @Autowired
    private HelloService helloService;

    @Operation(summary = "hello接口")
    @GetMapping("/{name}")
    public String hello(@PathVariable("name") String name) {
        return helloService.sayHello(name);
    }
}

三、Spring、Spring MVC和Springboot的常见注解

Spring、Spring MVC 和 Spring Boot 提供了丰富的注解简化开发,以下是三类框架中最常用的注解分类总结:

1.Spring 核心注解

主要用于 IoC 容器管理、依赖注入、AOP 等核心功能。

  1. IoC 容器相关

    • @Component:标记类为 Spring 组件,自动扫描并注册到容器(通用组件)。
    • @Controller:特殊的 @Component,标记类为 MVC 控制器(归为 Spring MVC 但基于 Spring 核心)。
    • @Service:特殊的 @Component,标记类为业务逻辑层服务。
    • @Repository:特殊的 @Component,标记类为数据访问层(DAO),自动转换数据库异常。
    • @Scope:指定 Bean 的作用域(如 singleton 单例、prototype 多例等)。
    • @Lazy:延迟初始化 Bean(仅在首次使用时创建)。
  2. 依赖注入相关

    • @Autowired:自动注入依赖(默认按类型匹配,结合 @Qualifier 按名称匹配)。
    • @Qualifier:与 @Autowired 配合,指定注入 Bean 的名称。
    • @Resource:JDK 注解,按名称注入依赖(默认名称,可指定 name 或 type)。
    • @Value:注入配置文件中的属性值(如 @Value("${server.port}"))。
  3. AOP 相关

    • @Aspect:标记类为切面类。
    • @Pointcut:定义切入点(如 execution(* com.example.service.*.*(..)))。
    • @Before/@After/@AfterReturning/@AfterThrowing/@Around:定义通知(增强逻辑)。
  4. 其他核心注解

    • @Configuration:标记类为配置类(替代 XML 配置)。
    • @Bean:在配置类中定义 Bean(方法返回值作为容器中的 Bean)。
    • @Profile:根据环境激活不同配置(如 dev/test/prod 环境)。
    • @Conditional:基于条件判断是否注册 Bean(Spring Boot 自动配置的基础)。

2.Spring MVC 注解

主要用于 Web 层请求处理、参数绑定、视图跳转等。

  1. 请求映射

    • @RequestMapping:映射 HTTP 请求(支持 value 路径、method 请求方法、params 参数等)。
    • @GetMapping:简化 @RequestMapping(method = RequestMethod.GET),处理 GET 请求。
    • @PostMapping:简化处理 POST 请求。
    • @PutMapping/@DeleteMapping:对应 PUT/DELETE 请求方法。
  2. 参数绑定

    • @PathVariable:获取 URL 路径中的参数(如 /user/{id} 中的 id)。
    • @RequestParam:获取请求参数(如 ?name=xxx),可指定是否必传、默认值。
    • @RequestBody:接收请求体中的 JSON/XML 数据(通常用于 POST/PUT 请求)。
    • @RequestHeader:获取请求头信息(如 AcceptCookie)。
    • @CookieValue:获取指定 Cookie 的值。
    • @ModelAttribute:将请求参数绑定到模型对象,或在方法执行前向模型添加属性。
  3. 响应处理

    • @ResponseBody:将方法返回值直接作为响应体(不经过视图解析,常用于 JSON 接口)。
    • @RestController:组合 @Controller 和 @ResponseBody,标记类为 REST 接口控制器。
    • @ResponseStatus:指定方法返回的 HTTP 状态码(如 HttpStatus.CREATED)。
  4. 异常处理

    • @ControllerAdvice:全局异常处理类(结合 @ExceptionHandler 使用)。
    • @ExceptionHandler:处理指定类型的异常(如 @ExceptionHandler(NullPointerException.class))。

3.Spring Boot 注解

基于 Spring 和 Spring MVC 扩展,用于简化配置、自动配置等。

  1. 启动类相关

    • @SpringBootApplication:Spring Boot 核心注解,组合以下三个注解:
      • @SpringBootConfiguration:标记类为配置类(继承 @Configuration)。
      • @EnableAutoConfiguration:开启自动配置(核心,加载 META-INF/spring.factories 中的配置类)。
      • @ComponentScan:自动扫描并注册组件(默认扫描当前类所在包及子包)。
  2. 配置相关

    • @ConfigurationProperties:将配置文件中的属性绑定到 Java 类(如 prefix = "user" 绑定 user.name 等)。
    • @EnableConfigurationProperties:启用 @ConfigurationProperties 注解的类(使其被 Spring 管理)。
    • @PropertySource:加载指定的自定义配置文件(如 @PropertySource("classpath:custom.properties"))。
  3. 条件注解(自动配置核心)

    • @ConditionalOnClass:类路径存在指定类时生效。
    • @ConditionalOnMissingClass:类路径不存在指定类时生效。
    • @ConditionalOnBean:容器中存在指定 Bean 时生效。
    • @ConditionalOnMissingBean:容器中不存在指定 Bean 时生效(用户自定义 Bean 优先)。
    • @ConditionalOnProperty:配置文件中存在指定属性且值匹配时生效(如 @ConditionalOnProperty(prefix = "server", name = "port", havingValue = "8080"))。
    • @ConditionalOnWebApplication/@ConditionalOnNotWebApplication:判断是否为 Web 应用。

四、相关面试问题

1.SpringMVC的执行流程?

        SpringMVC的执行流程包含以下步骤:

        第一,用户端发送请求给前端处理器DispatcherServlet,前端处理器接收请求并进行统一处理。

        第二,DispatcherServlet调用处理映射器HandleMapping找到具体的处理器,处理映射器返回处理器对象和响应的拦截器。

        第三,DispatcherServlet调用处理适配器HandlerAdapter适配并调用相应的处理器Controller,处理器处理完成后返回ModelAndView对象。

        第四,DispatcherServlet调用视图解析器ViewResolver解析并返回视图View对象。

        第五,DispatcherServlet渲染视图并响应用户。

        以上是使用JSP视图阶段的执行流程,对于现在常用的前后端分离阶段流程,不同的是在具体处理器处理完成后返回的不是ModelAndView,而是在方法上添加@ResponseBody注解,通过HttpMessageConverter来返回结果转换为JSO并响应。

2.Springboot自动配置原理?

        Springboot的自动装配原理依赖于@SpringBootApplication注解,它封装了@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan。其中@EnableAutoConfiguration注解是实现自动装配的核心,该注解又组合了@Import注解,导入了AutoConfigurationImportSelector类,实现了 selectImports方法,这个方法经过层层调用,最终会读取META-INF 目录下的后缀名为imports的文件或者spring.factories文件。读取到全类名了之后,会解析注册条件,把满足注册条件的Bean对象自动注入到IOC容器中

3.Spring 的常见注解有哪些?

      Spring的常见注解包括:

  1. 声明Bean的注解:@Component@Service@Repository@Controller

  2. 依赖注入相关注解:@Autowired@Qualifier@Resource

  3. 设置作用域的注解:@Scope

  4. 配置相关注解:@Configuration@ComponentScan@Bean

  5. AOP相关注解:@Aspect@Before@After@Around@Pointcut

4.SpringMVC常见的注解有哪些?

SpringMVC的常见注解有:

  • @RequestMapping:映射请求路径。

  • @RequestBody:接收HTTP请求的JSON数据。

  • @RequestParam:指定请求参数名称。

  • @PathVariable:从请求路径中获取参数。

  • @ResponseBody:将Controller方法返回的对象转化为JSON。

  • @RequestHeader:获取请求头数据。

  • @PostMapping@GetMapping等。

5.Springboot常见注解有哪些?

Spring Boot的常见注解包括:

  • @SpringBootApplication:由@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan组成。

  • 其他注解如@RestController@GetMapping@PostMapping等,用于简化Spring MVC的配置。