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

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>
时间: 2024-09-28 10:54:11

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

《Spring MVC学习指南(第2版)》——第1章 Spring框架 1.1XML配置文件

第1章 Spring框架 Spring框架是一个开源的企业应用开发框架,作为一个轻量级的解决方案,它包含20多个不同的模块.本书主要关注Core.Spring Bean.Spring MVC和Spring MVC Test模块. 本章主要介绍Core和Spring Bean这两个模块,以及它们如何提供依赖注入解决方案.为方便初学者,本书会深入讨论依赖注入概念的细节.后续介绍开发MVC应用的章节将会使用到本章介绍的技能. 依赖注入 简单来说,依赖注入的情况如下. 有两个组件A和B,A依赖于B.假定

《Spring MVC学习指南(第2版)》——导读

前言 Spring MVC是Spring框架中用于Web应用快速开发的一个模块.Spring MVC的MVC是Model-View-Controller的缩写.它是一个广泛应用于图形化用户交互开发中的设计模式,不仅常见于Web开发,也广泛应用于如Swing和JavaFX等桌面开发. 作为当今业界最主流的Web开发框架,Spring MVC(有时也称Spring Web MVC)的开发技能相当热门.本书可供想要学习如何通过Spring MVC开发基于Java的Web应用的开发人员阅读. HTTP使

《Spring MVC学习指南(第2版)》——2.7 小结

2.7 小结 在本章中,我们学习了基于MVC模式的模型2架构以及如何基于servlet控制器或者filter分发器开发一个模型2应用.两个示例分别为appdesign1和appdesign2.使用servlet作为过滤器上的控制器,一个明显的优点是你可以将servlet配置为欢迎页面. 在模型2应用程序中,JSP页面通常用做视图,当然也可以使用其他技术,如Apache Velocity和FreeMarker. 如果JSP页面用做模型2体系结构中的视图,那些页面仅用于显示值,并且不应在其中显示脚本

《Spring MVC学习指南(第2版)》——第2章 模型2和MVC模式 2.1模型1介绍

第2章 模型2和MVC模式 Java Web应用开发中有两种设计模型,为了方便,分别称为模型1和模型2.模型1是以页面中心,适合于小应用开发.而模型2基于MVC模式,是Java Web应用的推荐架构(简单类型的应用除外). 本章将会讨论模型2,并展示4个不同示例应用.第一个应用是一个基本的模型2应用,采用Servlet作为控制器:第二个应用也是模型2应用,但采用了Filter作为控制器:第三个应用引入了验证控件来校验用户的输入:最后一个应用则采用了一个自研的依赖注入器.在实践中,应替换为Spri

《Spring MVC学习指南(第2版)》——1.3 小结

1.3 小结 本章学习了依赖注入的概念以及基于Spring容器的实践,后续将在此基础之上配置Spring应用.

《Spring MVC学习指南(第2版)》——2.6 依赖注入

2.6 依赖注入 在过去数年间,依赖注入技术作为代码可测试性的一个解决方案已经广泛应用.实际上,Spring.Struts2等伟大框架都采用了依赖注入技术.那么,什么是依赖注入技术? 有两个组件A和B,A依赖于B.假定A是一个类,且A有一个方法importantMethod使用到了B,如下: public class A { public void importantMethod() { B b = ... // get an instance of B b.usefulMethod(); ..

《Spring MVC学习指南(第2版)》——2.5 校验器

2.5 校验器 在Web应用执行action时,很重要的一个步骤就是进行输入校验.校验的内容可以是简单的,如检查一个输入是否为空,也可以是复杂的,如校验信用卡号.实际上,因为校验工作如此重要,Java社区专门发布了JSR 303 Bean Validation以及JSR 349 Bean Validation 1.1版本,将Java世界的输入检验进行标准化.现代的MVC框架通常同时支持编程式和声明式两种校验方法.在编程式中,需要通过编码进行用户输入校验,而在声明式中,则需要提供包含校验规则的XM

《Spring MVC学习指南(第2版)》——2.3 模型2之Servlet控制器

2.3 模型2之Servlet控制器 为了便于对模型2有一个直观的了解,本节将展示一个简单模型2应用.实践中,模型2的应用非常复杂. 示例应用名为appdesign1,其功能设定为输入一个产品信息.具体为:用户填写产品表单(图2.2)并提交:示例应用保存产品并展示一个完成页面,显示已保存的产品信息(见图2.3). 图2.2 产品表单 图2.3 产品详细页 示例应用支持如下两个action. (1)展示"添加产品"表单.该action将图2.2中的输入表单发送到浏览器上,其对应的URI应

《Spring MVC学习指南(第2版)》——2.4 模型2之Filter分发器

2.4 模型2之Filter分发器 虽然servlet是模型2应用程序中最常见的控制器,但过滤器也可以充当控制器.但请注意,过滤器没有作为欢迎页面的权限.仅输入域名时不会调用过滤器分派器.Struts 2使用过滤器作为控制器,是因为该过滤器也用于提供静态内容. 下面的例子(appdesign2)是一个采用filter分发器的模型2应用,目录结构如图2.5所示. 图2.5 appdesign2目录结构 JSP页面和Product类同appdesign1相同,但没有采用servlet作为控制器,而是