返回 登录
0

Spring控制反转容器的使用

阅读1047

本篇主要介绍Spring如何管理bean和依赖关系。

通过构造器创建一个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
<a>http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"></a>

    <bean name="product" class="app01a.bean.Product"/>
</beans>

该bean的定义告诉Spring通过默认无参的构造器来初始化Product类。如果不存在该构造器(如果类作者重载了构造器,且没有显示声明默认构造器),则Spring将抛出一个异常。

注意,应采用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());

通过工厂方法创建一个bean实例

除了通过类的构造器方式,Spring还同样支持通过调用一个工厂的方法来初始化类。下面的bean定义展示了通过工厂方法来实例化java.util.Calendar。

<bean id="calendar" class="java.util.Calendar"
    factory-method="getInstance"/>

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

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

Destroy Method的使用

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

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

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

向构造器传递参数

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

清单1.2 Product类

package app01a.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="app01a.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="app01a.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>

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

Setter方式依赖注入

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

清单1.3 Employee类

package app01a.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 app01a.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="app01a.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="app01a.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.3所示的Employee类提供了一个可以传递参数的构造器,我们还可以将Address对象通过构造器注入,如下所示:

<bean name="employee2" class="app01a.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="app01a.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>

本文摘自《Spring MVC学习指南》

图片描述

 Spring MVC是Spring框架中用于Web应用快速开发的一个模块,其中的MVC是Model-View-Controller的缩写。作为当今业界最主流的Web开发框架,Spring MVC已经成为当前最热门的开发技能,同时也广泛用于桌面开发领域。
 
  《Spring MVC学习指南》重在讲述如何通过Spring MVC来开发基于Java的Web应用。全书共计12章,分别从Spring框架、模型2和MVC模式、Spring MVC介绍、控制器、数据绑定和表单标签库、传唤器和格式化、验证器、表达式语言、JSTL、国际化、上传文件、下载文件多个角度介绍了Spring MVC。除此之外,本书还配有丰富的示例以供读者练习和参考。
  
关于作者:
Paul Deck,是一位资深的Spring Framework开发者,他曾经是How Tomcat Work一书的作者之一。

评论