白盒审计-Spring框架与SpringMVC

-- 控制反转与依赖注入 --

IoC容器

  • 简介: 是 Spring 的核心, 负责创建和管理对象 (Bean) 的整个生命周期
  • BeanFactory: IoC 容器的基础接口, 提供基本的 Bean 管理功能, 用的比较少
  • ApplicationContext: BeanFactory 的子接口, 继承了 BeanFactory 的所有功能, 并增加了更多企业级特性
  • IoC (控制反转) 与 DI (依赖注入):
    • 控制反转: 是软件工程中的一项原则, 将对象或程序部分的控制权转移给容器或框架, 容器根据配置创建对象 (Bean), 并自动建立依赖关系, 代码只需"被动接收"依赖
    • 依赖注入: 是实现 IoC 的一种模式, 核心思想为一个对象不应该自己去创建 (new) 它所依赖的对象, 而是由外部容器 (如 Spring 框架) 负责创建并“注入”给它, 实现起来即"容器通过构造函数/setter 方法等方式, 将依赖对象主动注入目标对象 (Bean) 中"
    • 优点: 解耦 并提高可测试性 (比如在测试时, 可使用 DI 注入 Mock 对象, 专门用于测试)

SpringBean

  • 概念: 类似于装有对象的特殊的全局变量, 存在独特的生命周期和作用域
  • 作用域: 可通过配置 scope 来设置
    • Singleton: 默认值, IoC 容器中只有一个 Bean 实例, 所有组件获取的都是同一个对象 (内存地址相同)
    • Prototype: 每次获取 Bean 时 (getBean), 容器都会创建一个新的实例 (Prototype 作用域 Spring 容器不会销毁 Bean, 需要客户端自行管理资源的释放)
    • Request: 每次 HTTP 请求都会产生一个新的 Bean
    • Session: 同一个 HTTP Session 共享一个 Bean

Bean的注册/使用流程

  • 通过 applicationContext.xml 注册

配置 SpringBean 的实现类 (Spring 的 Bean 要求比 JavaBean 要宽松):

@Component // 通用注解,标记该类为SpringBean,除此之外还有其派生注解@Service/@Repository/@Controller,本质都相同
public class <Bean的实现类名> {  
    /* setter注入,对应属性需要有对应的公有setter方法(getter方法可选),字段可以是公有(但推荐私有)
       使用setter注入本质上是调用类的无参构造函数实例化对象后,再使用setter方法赋值,所以必须要有无参构造函数
       (注意:定义了有参构造函数后,编译器将不再自动生成默认的无参构造函数) */
    private String name;
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }
    ...

    /* 构造函数注入,需要拥有对应的构造函数,字段可以是公有(但推荐私有) */
    private String address;
    private int age;
    public <Bean的实现类名>(String address, int age){
        this.address = address;
        this.age = age;
    }  
    ...

    /* 字段注入,该种方式必须用注解 */
    @Autowired
    private String profession;
}

通过配置 applicationContext.xml 注册 Bean (该种注册不需要注解):

<?xml version="1.0" encoding="UTF-8"?>  
<beans  
        xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans  
               http://www.springframework.org/schema/beans/spring-beans-5.3.xsd"> 
    <!-- 扫描所在包下的Bean,并自动注册(可用base-package="<包名>"指定扫描的包)-->
    <!-- 扫描到Bean后,会按照依赖注入注解,先通过构造函数注入,再进行字段注入,再进行Setter方法注入 -->
    <context:component-scan/>  
    <!-- 手动注册Bean:setter注入 -->
    <bean id="<Bean的名字>" class="<Bean的实现类的全限定名>" scope="<bean的作用域scope,可选>">  
        <property name="<成员名>" value="要赋予的值"></property>  
        <property name="<成员名>" ref="<当赋予的值为另外一个Bean时,这里填Bean的id>"></property>  
        ...
    </bean>
    <!-- 手动注册Bean:构造函数注入 -->
    <bean id="<Bean的名字>" class="<Bean的实现类的全限定名>" scope="<bean的作用域scope,可选>">  
        <constructor-arg index="0" value=要赋予的值/> <!-- 第一个参数 -->
        <constructor-arg index="1" ref="<当赋予的值为另外一个Bean时,这里填Bean的id>"/>  <!-- 第二个参数 -->
        ...
    </bean>
    ...
</beans>
  • 通过 java 配置类注册 (需要注解)
@Configuration // 标识这个是配置类(相当于<beans>标签)
@ComponentScan // 可选,扫描所在包下的Bean,并自动注册,可用basePackages="<包名>"指定扫描的包,
               // ComponentScan扫描到Bean后,会按照依赖注入注解,先通过构造函数注入,再进行字段注入,再进行Setter方法注入
public class AppConfig { // AppConfig是约定名称,实际可以任意使用
    @Bean // 手动注册Bean(方法名作为Bean的名字,相当于XML中的<bean>标签)
    public <返回值类型> <方法名(Bean的名字)>(形参,...){
        ... // 在代码块里手动实现Setter注入/构造函数注入
        return xxx; // 返回值会被注册为Bean
    }
    ...
}
  • 使用 Bean
-- 使用BeanFactory(Spring3.1后被标记过时,但仍可用) --
// 注:BeanFactory采用懒加载,只有在getBean时才创建对象
/* 引入 */
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;  
import org.springframework.core.io.Resource;

/* 实现代码 */
Resource resource=new ClassPathResource("applicationContext.xml");
BeanFactory factory=new XmlBeanFactory(resource);

/* 获取Bean */
<Bean的实现类> <变量名> = (<Bean的实现类>)factory.getBean("<Bean的名字>")

-- 使用ApplicationContext --
// 注: ApplicationContext在容器启动时就会预加载所有的单粒Bean
/* 引入 */
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/* 实现代码 */
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

/* 获取Bean */
<Bean的实现类> <变量名> = (<Bean的实现类>)context.getBean("<Bean的名字>")

Bean注解

注册Bean

  • @Component: 用于标识一个类为 SpringBean (用于非特定层的类, 即非 Controller/Service)
  • @Respository: 用于标识一个类为 SpringBean (用于 DAO 层-数据访问层的类), 能将数据库访问抛出的特定异常转换为 Spring 的数据访问异常
  • @Service: 用于标识一个类为 SpringBean (用于 Service 层-业务逻辑层的类), 主要用于处理复杂的业务逻辑
  • @Controller: 用于标识一个类为 SpringBean (用于 Web 层-控制层的类), 通常与 @RequestMapping 配合使用, 处理 HTTP 请求

配置类

  • @Configuration: 用于标识一个类为配置类 (注: 配置类本身也是一个 Bean)
  • @Bean: 标注在 (配置类的) 方法上, 告诉 Spring 该方法返回的对象应该被当作 Bean 注册, 用于手动注册 Bean
  • @ComponentScan(basePackages = "<包名>"): 标注在配置类上, 其会扫描对应包中的 Bean (包括配置类), 然后注册 (若不写包名, 默认扫描配置类所在包)
  • @Import({类名1.class, ...}): 标注在配置类上, 单独对指定的 Bean 进行注册

依赖注入

  • @Autowired
    • 应用场景: 可以用在 字段、构造函数、Setter 方法、方法参数上
    • 作用: 先按类型, 再按名字
      • 按类型装配, 在上下文中查找与类型匹配的 Bean, 并注入
      • 若没找到类型匹配的 Bean, 则抛出异常; 若找到唯一一个, 则直接注入;
      • 若找到多个, 若无 @Qualifier, 试查找 BeanID 与字段/参数名相同的 Bean 来注入, 若没找到则抛出异常
    • 参数: require=<boolean>: 当没找到 Bean 时, 是否抛出异常, 而非将字段/参数值设置为 null, 默认为 true (注: 当只有一个构造函数时, 默认会被当作被 @Autowired 标注)
  • @Qualifier("<BeanId>")
    • 应用场景: 可以用在 字段、方法参数上
    • 作用: 当使用 @Autowired, 存在多个相同类型的 Bean 时, 通过 @Qualifier 指定注入哪一个名称的 Bean, 若没找到则抛出异常 (除非 require=false)
  • @Resource
    • 应用场景: 可以用在 字段、构造函数、Setter 方法、方法参数上
    • 作用: 先按名字, 再按类型
      • 按名字装配, 在上下文中查找 id 与字段/参数名匹配的 Bean, 并注入
      • 如果按名称没找到, 按类型查找, 若找到唯一一个, 则直接注入; 若没找到或找到多个, 则报错
    • 参数: name="<BeanId>": 直接指定注入的 BeanId
  • @Value
    • 应用场景: 可以用在 字段、方法参数上
    • 作用: 用于注入各种值
      • 注入 SpEL 表达式的值: @Value(#{...})
      • 注入字面量字符串: @Value("<字符串>")
      • 注入 Resource 资源: @Value("<路径字符串>") (当注入的字段/参数类型为 Resource 时, 会自动将路径字符串转换为 Resource 对象)
      • 注入外部值: @Value(${<键名>})@Value(${<键名>:<默认值>}) (若未找到则使用默认值) 包括在 application.propertiesapplication.yml 中定义键, 系统环境变量, JVM 系统属性, random (随机数)

-- SpringMVC --

依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${org.springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org.springframework.version}</version>
</dependency>

简介

  • MVC: 一种软件架构模式, 将应用程序划分为 Model (模型) - View (视图) - Controller (控制器) 三个组件, 旨在实现逻辑处理与界面展示的解耦
  • Model (模型): 用于处理数据与业务逻辑
    • 实体类 Bean (数据载体): 专门存储业务数据, 无业务逻辑, 是 JavaBean
    • 业务 Bean (逻辑中枢): 包含 Service (业务逻辑层) 和 Dao (数据访问层), 负责数据的增删改查与规则约束, 是单例 SpringBean
  • View (视图): 负责数据展示与交互
    • 传统视图: 指工程中的 html 或 jsp 等服务端渲染的页面
    • 现代视图: 前后端分离的架构中, JSON/XML 响应数据也是一种视图表现形式, 交由前端框架渲染
  • Controller (控制器): 负责协调 Model 与 View 的交互, 接收请求与处理响应
    • 前端控制器 (DispatcherServlet): Servlet, 框架的统一入口和调度中心, 负责接收请求并分发给具体的 Handler
    • 业务控制器 (Handler): 开发者使用 @Controller/@RestController 编写的 Java 类, 负责处理具体的业务请求, 本质上是 SpringBean
    • 配合: Spring MVC 采用了“前端控制器模式”, 即 1 个 Servlet (DispatcherServlet) + N 个 Controller (Handler)

工作流程

  1. 请求到达: 用户发送 HTTP 请求, 被 DispatcherServlet 捕获 (通常在 web.xml 中的 <servlet> 或 JavaConfig 中定义捕获规则)
  2. 查找 Handler: DispatcherServlet 调用 HandlerMapping (处理器映射器), 根据 URL (通常通过扫描 @Controller 类中带有 @RequestMapping 注解的方法) 找到对应的 Handler 及其拦截器链
  3. 适配执行: DispatcherServlet 调用 HandlerAdapter (处理器适配器) 来执行 Handler (将 HTTP 请求参数赋值给 Handler 形参)
  4. 业务处理: Handler (Controller) 执行业务逻辑
    • 情况 A (页面跳转): 返回 ModelAndView 对象
    • 情况 B (API 接口): 标注 @ResponseBody, 直接返回数据对象
  5. 渲染/响应:
    • 情况 A: ViewResolver 将逻辑视图名 (如 "success") 解析为具体的视图对象 (如 success.html), View 渲染视图并返回 HTML
    • 情况 B: HttpMessageConverter 将数据对象序列化为 JSON 写入响应流

常用注解

控制器定义

  • @Controller: 标识一个类为控制器 (也即 Handler)
  • @ResponseBody: 标识该控制器返回的是 Json 数据 (若不使用, 控制器返回默认被看作页面路径), Spring 会将返回的对象转换为 Json 格式发送给前端
  • @RestController: 相当于 @Controller + @ResponseBody

请求路径映射

  • @RequestMapping: 可标注在控制器及其方法上, 用于映射请求路径 (实际请求路径为 控制器映射路径+方法映射路径)
    • @GetMapping/@PostMapping/@PutMapping/@DeleteMapping: 标识特定方法的映射 (@RequestMapping 默认会接收所有的请求方法的请求)

参数绑定

  • @RequestBody: 提取 HTTP 请求体中的 JSON/XML 数据, 并自动反序列化为 Java 对象 (默认通过 Jackson 实现)
    • 绑定参数类型: 可绑定 Map<String, Object> 参数; 常绑定 JavaBean 参数, Spring 会根据 JSON 的键名与 Java 对象的属性名进行匹配, 并调用 setter 方法注入 (该 JavaBean 需要存在无参构造函数, 否则无法实例化 Bean)
  • @RequestParam: 提取 URL 中的查询参数/表单提交的参数
    • 绑定参数类型: 基本数据类型及其包装类 (Spring 会自动尝试将字符串参数转换为目标类型); 集合/数组; Map<String, String>; MultipartFile
    • 注解参数:
      • required: 默认为 true, 设置参数是否必选, 为 true 时即当前端没传该参数时, 后端会直接报错 400 Bad Request
      • defaultValue: 设置当参数缺失时的默认值
  • @PathVariable: 提取路径映射注解中的动态路径参数 (用 {参数名} 标识)
    • 绑定的参数的类型: 基本数据类型及其包装类 (Spring 会自动尝试将字符串参数转换为目标类型)
  • @ModelAttribute:
    1. 参数绑定:将请求参数(通常是 Form 表单)绑定到 Java Bean 对象。
    2. 数据预加载:如果标注在方法上,该方法会在控制器其他方法执行前先执行,常用于在 Model 中预先放入一些公共数据
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇