《Spring MVC学习指南(第2版)》——1.2 Spring控制反转容器的使用

简介: 该bean的定义告诉Spring,通过默认无参的构造器来初始化Product类。如果不存在该构造器(如果类的编写者重载了构造器,且没有显示声明默认构造器),则Spring将抛出一个异常。此外,该无参数的构造器并不要求是public签名。

本节书摘来自异步社区《Spring MVC学习指南(第2版)》一书中的第1章,第1.2节,作者:【美】Paul Deck著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.2 Spring控制反转容器的使用

本节主要介绍Spring如何管理bean和依赖关系。
1.2.1 通过构造器创建一个bean实例
前面已经介绍,通过调用ApplicationContext的getBean方法可以获取一个bean的实例。下面的配置文件中定义了一个名为product的bean(见清单1.1)。

清单1.1 一个简单的配置文件

< ?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.xsd">

  < bean name="product" class="springintro.bean.Product"/>

< /beans>

该bean的定义告诉Spring,通过默认无参的构造器来初始化Product类。如果不存在该构造器(如果类的编写者重载了构造器,且没有显示声明默认构造器),则Spring将抛出一个异常。此外,该无参数的构造器并不要求是public签名。

注意,应采用id或者name属性标识一个bean。为了让Spring创建一个Product实例,应将bean定义的name值“product”(具体实践中也可以是id值)和Product类型作为参数传递给ApplicationContext的getBean方法。

ApplicationContext context =
    new ClassPathXmlApplicationContext(
    new String[] {"spring-config.xml"});
Product product1 = context.getBean("product", Product.class);
product1.setName("Excellent snake oil");
System.out.println("product1: " + product1.getName());

1.2.2 通过工厂方法创建一个bean实例
大部分类可以通过构造器来实例化。然而,Spring还同样支持通过调用一个工厂的方法来初始化类。

下面的bean定义展示了通过工厂方法来实例化java.time.LocalDate。

<bean id="localDate" class="java.time.LocalDate"
  factory-method="now"/>

本例中采用了id属性而非name属性来标识bean,采用了getBean方法来获取LocalDate 实例。

ApplicationContext context =
    new ClassPathXmlApplicationContext(
    new String[] {"spring-config.xml"});
LocalDate localDate = context.getBean("localDate", LocalDate.class);

1.2.3 销毁方法的使用
有时,我们希望一些类在被销毁前能执行一些方法。Spring考虑到了这样的需求。可以在bean定义中配置destroy-method属性,来指定在销毁前要执行的方法。

下面的例子中,我们配置Spring通过java.util.concurrent.Executors的静态方法newCached ThreadPool来创建一个java.uitl.concurrent.ExecutorService实例,并指定了destroy-method属性值为shutdown方法。这样,Spring会在销毁ExecutorService实例前调用其shutdown方法。

<bean id="executorService" class="java.util.concurrent.Executors"
  factory-method="newCachedThreadPool"
  destroy-method="shutdown"/>

1.2.4 向构造器传递参数
Spring支持通过带参数的构造器来初始化类(见清单1.2)。

清单1.2 Product类

package springintro.bean;
import java.io.Serializable;

public class Product implements Serializable {
  private static final long serialVersionUID = 748392348L;
  private String name;
  private String description;
  private float price;

  public Product() {
  }

  public Product(String name, String description, float price) {
    this.name = name;
    this.description = description;
    this.price = price;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
  public float getPrice() {
    return price;
  }
  public void setPrice(float price) {
    this.price = price;
  }
}

以下的定义展示了如何通过参数名传递参数。

<bean name="featuredProduct" class="springintro.bean.Product">
  <constructor-arg name="name" value="Ultimate Olive Oil"/>
  <constructor-arg name="description"
    value="The purest olive oil on the market"/>
  <constructor-arg name="price" value="9.95"/>
</bean>
这样,在创建Product实例时,Spring会调用如下构造器:

public Product(String name, String description, float price) {
  this.name = name;
  this.description = description;
  this.price = price;
}

除了通过名称传递参数外,Spring还支持通过指数方式来传递参数,具体如下:

<bean name="featuredProduct2" class="springintro.bean.Product">
  <constructor-arg index="0" value="Ultimate Olive Oil"/>
  <constructor-arg index="1"
    value="The purest olive oil on the market"/>
  <constructor-arg index="2" value="9.95"/>
</bean>

需要说明的是,采用这种方式,对应构造器的所有参数必须传递,缺一不可。

1.2.5 Setter方式依赖注入
下面以Employee类和Address类为例,介绍setter方式依赖注入(见清单1.3和清单1.4)。

清单1.3 Employee类

package springintro.bean;

public class Employee {
  private String firstName;
  private String lastName;
  private Address homeAddress;

  public Employee() {
  }

  public Employee(String firstName, String lastName, Address
    homeAddress) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.homeAddress = homeAddress;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public Address getHomeAddress() {
    return homeAddress;
  }

  public void setHomeAddress(Address homeAddress) {
    this.homeAddress = homeAddress;
  }

  @Override
  public String toString() {
    return firstName + " " + lastName
        + "\n" + homeAddress;
  }
}

清单1.4 Address类

package springintro.bean;

public class Address {
 private String line1;
  private String line2;
  private String city;
  private String state;
  private String zipCode;
  private String country;

  public Address(String line1, String line2, String city,
      String state, String zipCode, String country) {
    this.line1 = line1;
    this.line2 = line2;
    this.city = city;
    this.state = state;
    this.zipCode = zipCode;
    this.country = country;
  }

  // getters and setters omitted

  @Override
  public String toString() {
    return line1 + "\n"
        + line2 + "\n"
        + city + "\n"
        + state + " " + zipCode + "\n"
        + country;
  }
}

Employee依赖于Address类,可以通过如下配置来保证每个Employee实例都能包含Address实例。

<bean name="simpleAddress" class="springintro.bean.Address">
  <constructor-arg name="line1" value="151 Corner Street"/>
  <constructor-arg name="line2" value=""/>
  <constructor-arg name="city" value="Albany"/>
  <constructor-arg name="state" value="NY"/>
  <constructor-arg name="zipCode" value="99999"/>
  <constructor-arg name="country" value="US"/>
</bean>

<bean name="employee1" class="springintro.bean.Employee">
  <property name="homeAddress" ref="simpleAddress"/>
  <property name="firstName" value="Junior"/>
  <property name="lastName" value="Moore"/>
</bean>

simpleAddress对象是Address类的一个实例,它通过构造器方式实例化。employee1对象则通过配置property元素来调用setter方法以设置值。需要注意的是,homeAddress属性配置的是simpleAddress对象的引用。

被引用对象的配置定义无需早于引用其对象的定义。在本例中,employee1对象可以出现在simpleAddress对象定义之前。

1.2.6 构造器方式依赖注入
清单1.3所示的Employee类提供了一个可以传递参数的构造器,我们还可以将Address对象通过构造器注入,如下所示:

<bean name="employee2" class="springintro.bean.Employee">
  <constructor-arg name="firstName" value="Senior"/>
  <constructor-arg name="lastName" value="Moore"/>
  <constructor-arg name="homeAddress" ref="simpleAddress"/>
</bean>

<bean name="simpleAddress" class="springintro.bean.Address">
  <constructor-arg name="line1" value="151 Corner Street"/>
  <constructor-arg name="line2" value=""/>
  <constructor-arg name="city" value="Albany"/>
  <constructor-arg name="state" value="NY"/>
  <constructor-arg name="zipCode" value="99999"/>
  <constructor-arg name="country" value="US"/>
</bean>
相关文章
|
前端开发 Java 测试技术
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
本文介绍了 `@RequestParam` 注解的使用方法及其与 `@PathVariable` 的区别。`@RequestParam` 用于从请求中获取参数值(如 GET 请求的 URL 参数或 POST 请求的表单数据),而 `@PathVariable` 用于从 URL 模板中提取参数。文章通过示例代码详细说明了 `@RequestParam` 的常用属性,如 `required` 和 `defaultValue`,并展示了如何用实体类封装大量表单参数以简化处理流程。最后,结合 Postman 测试工具验证了接口的功能。
916 0
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
|
9月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
9月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
9月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
775 2
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
1603 0
|
12月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
822 0
|
12月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
366 0
|
12月前
|
JSON 前端开发 Java
第05课:Spring Boot中的MVC支持
第05课:Spring Boot中的MVC支持
441 0
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
393 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?