Spring MVC -- Spring框架入门(IoC、DI以及XML配置文件)

Spring MVC是Spring框架中用于Web应用开发的一个模块。Spring MVC的MVC是Model-View-Controller的缩写。它是一个普遍应用于图像化用户交互开发中的设计模式,不只常见于Web开发,也普遍应用于如Swing和JavaFX等桌面开发。html

Spring MVC基于Spring框架、Servlet和JSP(JavaServer Page),在掌握这3门技术的基础上学习Spring MVC将很是容易。java

Spring框架是一个开源的企业应用开发框架,做为一个轻量级的解决方案,它包含20多个不一样的解决方法。咱们主要关注Core、Spring Bean、Spring MVC和Spring MVC Test模块。git

一 下载Spring

一、Spring下载

Spring框架下载官网:http://spring.io/projects,具体能够参考博客Spring框架下载方法程序员

也能够直接下载:URL为最Spring最新5.1.6版本地址,获取其余版本只需修改下面连接的5.1.6的版本号信息成想要的版本便可:https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring/5.1.6.RELEASEgithub

将下载好的zip解压到任意目录,在解压的目录中,包含相应的文档和Java源代码,其中libs文件下为基于Spring框架开发应用所须要的jar文件。web

二、Spring依赖包下载

关于spring的spring-framework-3.0.2.RELEASE-dependencies.zip包的下载:http://s3.amazonaws.com/dist.springframework.org/release/SPR/spring-framework-3.0.2.RELEASE-dependencies.zipspring

三、下载Spring源码

Spring框架是一个开源项目,若是你想要还没有发布的最新版本的Spring,可使用在github上下载源代码:https://github.com/spring-projects/spring-frameworkexpress

二 IoC和DI

Spring框架有两个重要的概念:控制翻转、依赖注入。 apache

一、IoC是什么

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为什么是反转(有反转就应该有正转了),哪些方面反转了”,那咱们来深刻分析一下:编程

  • 谁控制谁,控制什么:传统Java SE程序设计,咱们直接在对象内部经过new进行建立对象,是程序主动去建立依赖对象;而IoC是有专门一个容器来建立这些对象,即由Ioc容器来控制对象的建立;谁控制谁?固然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不仅是对象包括好比文件等);
  • 为什么是反转,哪些方面反转了:有反转就有正转,传统应用程序是由咱们本身在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙建立及注入依赖对象;为什么是反转?由于由容器帮咱们查找及注入依赖对象,对象只是被动的接受依赖对象,因此是反转;哪些方面反转了?依赖对象的获取被反转了。

用图例说明一下,传统程序设计如图,都是主动去建立相关对象而后再组合起来:

当有了IoC/DI的容器后,在客户端类中再也不主动去建立这些对象了:

2  IoC能作什么

IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导咱们如何设计出松耦合、更优良的程序。传统应用程序都是由咱们在类内部主动建立依赖对象,从而致使类与类之间高耦合,难于测试;有了IoC容器后,把建立和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,因此对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得很是灵活。

其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序本来是老大,要获取什么资源都是主动出击,可是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来建立并注入它所须要的资源了。

IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找咱们,咱们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

三、IoC和DI

DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并不是为软件系统带来更多功能,而是为了提高组件重用的频率,并为系统搭建一个灵活、可扩展的平台。经过依赖注入机制,咱们只须要经过简单的配置,而无需任何代码就可指定目标须要的资源,完成自身的业务逻辑,而不须要关心具体的资源来自何处,由谁实现。

理解DI的关键是:“谁依赖谁,为何须要依赖,谁注入谁,注入了什么”,那咱们来深刻分析一下:

  • 谁依赖于谁:固然是应用程序依赖于IoC容器;
  • 为何须要依赖:应用程序须要IoC容器来提供对象须要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所须要的外部资源(包括对象、资源、常量数据)。

IoC和DI由什么关系呢?其实它们是同一个概念的不一样角度描述,因为控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),因此2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

注:若是想要更加深刻的了解IoC和DI,请参考大师级人物Martin Fowler的一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》,原文地址:http://www.martinfowler.com/articles/injection.html

四、依赖注入具体案例

有两个组件A和B,A依赖于B。假设A是一个类,且A有一个方法importantMethod用到了B,以下:

class B{
    public void usefulMethod() {}
}

public class A{
    public void importantMethod() {
        //get an instance of B
        B b = new B();
        b.usefulMethod();
    }
}

要使用B,类A必须先得到组件B的实例引用。若B是一个具体类,则可经过new 关键字之间建立组件B的实例。可是,若是B是接口,且有多个实现,则问题就变得复杂了。咱们当然能够任意选择接口B的一个实现类,可是这意味着A的可重用性大大下降了,由于没法采用B的其余实现。

依赖注入是这样处理此类情景的:接管对象的建立工做,并将该对象的引用注入到须要该对象的组件中。以上述状况为例,依赖注入框架会分别建立对象A和对象B,而后将对象B注入到对象A中。

为了能让框架进行依赖注入,程序员须要编写特定的set方法或者构造方法。例如,为了能将B注入到A中,类A会被修改为以下形式:

public class A{
    private B b;
    public void importantMethod() {                
        b.usefulMethod();
    }
    
    public void setB(B b) {
        this.b = b;
    }
}

修改后的类A新增了一个set方法,该方法将会被框架调用,以注入B的一个实例。因为对象依赖由依赖注入,类A的importantMethod()方法再也不须要在调用B的usefulMethod()方法前去建立B的一个实例。

固然,也能够采用构造器方式注入,以下所示:

public class A{
    private B b;
    
    public A(B b) {
        this.b = b;
    }
    
    public void importantMethod() {                
        b.usefulMethod();
    }    
}

本例中,Spring会先建立B的实例,再建立A的实例,而后把B注入到实例中。

注:Spring管理的对象称为beans。

经过提供一个Ioc容器(或者说DI容器),Spring为咱们提供一种能够“聪明”的管理Java对象依赖关系的方法。其优雅之处在于,程序员无需了解Spring框架的存在,更不须要引入任何Spring类型。

五、ApplicationContext接口

使用Spring,程序几乎将全部重要对象的建立工做移交给Spring,并配置如何注入依赖。Spring支持XML或注解两种配置方式。此外,还须要建立一个ApplicationContext对象,表明一个Spring IoC容器,org.springframework.context.ApplicationContext接口有不少实现类,包括ClassPathXmlApplicationContext和FileSystemXmlApplicationContext。这两个实现都须要至少一个包含beans信息的XML文件。

  • ClassPathXmlApplicationContext:尝试在类加载路径中加载配置文件;
  • FileSystemXmlApplicationContext:从文件系统中加载配置路径。
/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context;

import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;

/**
 * Central interface to provide configuration for an application.
 * This is read-only while the application is running, but may be
 * reloaded if the implementation supports this.
 *
 * <p>An ApplicationContext provides:
 * <ul>
 * <li>Bean factory methods for accessing application components.
 * Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}.
 * <li>The ability to load file resources in a generic fashion.
 * Inherited from the {@link org.springframework.core.io.ResourceLoader} interface.
 * <li>The ability to publish events to registered listeners.
 * Inherited from the {@link ApplicationEventPublisher} interface.
 * <li>The ability to resolve messages, supporting internationalization.
 * Inherited from the {@link MessageSource} interface.
 * <li>Inheritance from a parent context. Definitions in a descendant context
 * will always take priority. This means, for example, that a single parent
 * context can be used by an entire web application, while each servlet has
 * its own child context that is independent of that of any other servlet.
 * </ul>
 *
 * <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory}
 * lifecycle capabilities, ApplicationContext implementations detect and invoke
 * {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware},
 * {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see ConfigurableApplicationContext
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.core.io.ResourceLoader
 */
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    /**
     * Return the unique id of this application context.
     * @return the unique id of the context, or {@code null} if none
     */
    @Nullable
    String getId();

    /**
     * Return a name for the deployed application that this context belongs to.
     * @return a name for the deployed application, or the empty String by default
     */
    String getApplicationName();

    /**
     * Return a friendly name for this context.
     * @return a display name for this context (never {@code null})
     */
    String getDisplayName();

    /**
     * Return the timestamp when this context was first loaded.
     * @return the timestamp (ms) when this context was first loaded
     */
    long getStartupDate();

    /**
     * Return the parent context, or {@code null} if there is no parent
     * and this is the root of the context hierarchy.
     * @return the parent context, or {@code null} if there is no parent
     */
    @Nullable
    ApplicationContext getParent();

    /**
     * Expose AutowireCapableBeanFactory functionality for this context.
     * <p>This is not typically used by application code, except for the purpose of
     * initializing bean instances that live outside of the application context,
     * applying the Spring bean lifecycle (fully or partly) to them.
     * <p>Alternatively, the internal BeanFactory exposed by the
     * {@link ConfigurableApplicationContext} interface offers access to the
     * {@link AutowireCapableBeanFactory} interface too. The present method mainly
     * serves as a convenient, specific facility on the ApplicationContext interface.
     * <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException
     * after the application context has been closed.</b> In current Spring Framework
     * versions, only refreshable application contexts behave that way; as of 4.2,
     * all application context implementations will be required to comply.
     * @return the AutowireCapableBeanFactory for this context
     * @throws IllegalStateException if the context does not support the
     * {@link AutowireCapableBeanFactory} interface, or does not hold an
     * autowire-capable bean factory yet (e.g. if {@code refresh()} has
     * never been called), or if the context has been closed already
     * @see ConfigurableApplicationContext#refresh()
     * @see ConfigurableApplicationContext#getBeanFactory()
     */
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

}
View Code

下面是从类加载路径中加载config1.xml和config2.xml的ApplicationContext建立的一个代码示例:

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"config1.xml","config2.xml"});

能够经过调用ApplicationContext的getBean()方法从IoC容器中得到对象:

Product product = context.getBean("product",Product.class);

genBean()方法会在xml配置文件中查询name(或id)为product且类型为Product的bean对象。

注:理想状况下,咱们只需在测试代码中建立一个ApplicationContext,应用程序自己无需处理。对于Spring MVC应用,能够经过一个Spring Servlet来处理ApplicationContext,而无需直接处理。

三 XML配置文件

从1.0版本开始,Spring就支持基于XML的配置;从2.5版本开始,增长了经过注解的配置文件。下面介绍如何配置XML文件,配置文件的根元素一般为beans:

<?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 ">
       ...
</beans>

若是须要更强的Spring配置能力,能够在schema location属性中添加相应的schema,也能够指定schema版本:http://www.springframework.org/schema/beans/spring-beans-5.1.xsd,不过推荐使用默认的schma,以便升级spring库时无需修改配置文件。

配置文件既能够是一份,也能够分解为多份,以支持模块化配置。ApplicationContext的实现类支持读取多份配置文件。另外一种选择是,经过一份主配置文件,将该文件导入到其余配置文件。

下面是导入其余配置文件的一个示例:

<?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 ">
       <import resource="config1.xml"/>
       <import resource="module2/config2.xml"/>
       <import resource="/resources/config3.xml"/>
       ...
</beans>

bean元素的配置在后面将会详细介绍。

四 Spring控制反转(IoC)容器的使用

本节将介绍Spring如何管理bean。

一、经过无参构造器建立一个bean实例

前面已经介绍,经过调用ApplicationContext的getBean()方法能够获取一个bean的实例。

下面咱们将建立一个名为spring-intro的Java Project项目,而后咱们须要导入5个Spring Jar包:

  • 从spring-framework-5.1.6.RELEASE\libs下复制

spring-beans-5.1.6.RELEASE.jar

spring-context-5.1.6.RELEASE.jar

spring-core-5.1.6.RELEASE.jar

spring-expression-5.1.6.RELEASE.jar

到当前项目中,右键当前项目JRE System Library——>Build Path——>Configure Build Path——>Add External JARs把这四个包导入;

  • 从spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.logging\1.1.1下复制

com.springsource.org.apache.commons.logging-1.1.1.jar

到当前项目中,右键当前项目JRE System Library——>Build Path——>Configure Build Path——>Add External JARs把这一个包导入;

若是是Dynamic Java Web项目,直接将这5个Jar包导入到WebContent/WEB-INF/lib便可。

下面为代码的编写,咱们先建立一个Product类,位于包springintro.bean中:

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;
    }
}

下面建立一个名为spring-config.xml的配置文件,其中定义了一个名为product的bean,该配置文件位于src文件夹下:

<?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类。若是不存在该构造器则会抛出一个异常。此外,该无参数的构造器并不要求是public签名。

注意:应采用id或者name属性标识一个bean。为了让Spring建立一个Product实例,应将bean定义的name值"product"和Product类型做为参数传给ApplicationContext的getBean()方法。

在包springintro下建立Main.java文件:

package springintro;

import java.time.LocalDate;
import java.util.Calendar;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import springintro.bean.Employee;
import springintro.bean.Product;

public class Main {
    public static void main(String[] args) {
        //建立IoC容器对象  从类路径下(/src)加载xml配置文件  容器启动时就会建立容器中配置的全部对象
        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());
  }
}

输出以下:

product1: Excellent snake oil

二、经过静态工厂方法建立一个bean实例

大部分类能够经过构造器来实例化。然而,Spring还一样支持经过调用一个工厂的静态方法来初始化类

下面的bean定义展现了经过静态工厂方法来实例化Java.time.LocalData,调用java.time.LocalDate的静态方法now()建立LocalDate 对象:

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

本例中采用了id属性而非name属性来标识bean,采用了getBean()方法来获取LocalData实例:

        LocalDate localDate = context.getBean("localDate", java.time.LocalDate.class);
        System.out.println("today:" + localDate);

输出以下:

today:2019-04-29

三、销毁方法的使用(bean元素的destroy-method属性)

有时,咱们但愿一些对象在被销毁前能执行一些方法。Spring考虑到这样的需求,能够在bean定义中配置destroy-method属性,来指定在销毁前要执行的方法。

下面的例子中,咱们配置Spring经过java.util.concurrent.Exceutors的静态方法newCachedThreadPool()来建立一个java.util.concurrent.ExceutorService实例,并指定了destroy-method属性值为shutdown()方法。这样,Spring会在销毁ExceutorService实例前调用shutdown()方法:

     <bean id="executorService" class="java.util.concurrent.Executors" 
         factory-method="newCachedThreadPool" 
         destroy-method="shutdown">
     </bean>
        ExecutorService executorService = context.getBean("executorService", ExecutorService.class);
        //强制关闭IoC容器,在容器关闭以前会销毁容器中全部对象  
        ((ClassPathXmlApplicationContext)context).close();

在程序中咱们强制关闭IoC容器,这样就会销毁ExceutorService实例,从而会触发executorService.shutdown()方法的执行。

四、初始化方法的使用(bean元素的init-method属性)

与销毁方法相对应的还有一个初始化方法,会在对象实例建立以后调用,能够在bean定义中配置init-method属性,来指定初始化要执行的方法:

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

五、bean元素的scope属性

  • singleton(默认值):单例模式,被标识为单例的对象,在IoC容器中只会存在一个实例;
  • prototype:多例,被标识为多例的对象,每次在获取时才会建立,每次建立都是新的对象,整合struct2时,ActionBean必须配置为多例的;

  • request(了解):web环境下,与request声明周期一致;
  • session(了解):web环境下,与session声明周期一致;

以下案例:

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

 

五 Spring依赖注入(DI)方式

本节将详细介绍Spring的依赖注入方式。

 一、构造器方式依赖注入

前面已经介绍了使用无参构造函数来初始化类,此外,Spring支持经过带参数的构造器来初始化类。

咱们仍然以Product类为例,如下的定义展现了如何经过Product类构造函数的参数名传递参数:

    <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>

这样,在IoC容器建立Product实例时,Spring会调用以下构造器:

        Product featuredProduct = context.getBean("featuredProduct", Product.class);
        System.out.println(featuredProduct.getName() + ", " + featuredProduct.getDescription()
                + ", " + featuredProduct.getPrice());
    public Product(String name, String description, float price) {
        this.name = name;
        this.description = description;
        this.price = price;
    }

输出以下:

Ultimate Olive Oil, The purest olive oil on the market, 9.95

除了经过参数名称传递参数外,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>

上面index="0",表示第一个参数传入"Ultimate Olive Oil",同理...

可是若是还存在一个构造函数以下:

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

咱们会发现这个参数名和以前的同样,而且顺序也同样,此时为了区分构造函数,咱们还须要指定type参数:

    <bean name="featuredProduct3" 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" type="java.lang.String" index="2"/>
    </bean>

若是构造函数的参数不是指类型,而是引用类型,则须要将value更改成ref。

二、Setter方式依赖注入

下面以Employee类和Address类为例,介绍setter方式依赖注入。

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;
    }

}

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;
    }

    public String getLine1() {
        return line1;
    }

    public void setLine1(String line1) {
        this.line1 = line1;
    }

    public String getLine2() {
        return line2;
    }

    public void setLine2(String line2) {
        this.line2 = line2;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    
    @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>

simpleAddress对象是Address类的一个实例,它经过构造器方式实例化。

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

employee1对象则经过配置property元素来调用setter方法以设置字段值。须要注意的是,homeAddress属性配置的是simpleAddress对象的引用。

被引用对象的配置定义无需早于引用其对象的定义,在本例中,employee1对象能够出如今simpleAddress对象定义以前。

这样,在IoC容器建立employee1实例时,Spring会调用默认构造器,并经过setter方法设置值:

        Employee employee1 = context.getBean("employee1", Employee.class);
        System.out.println(employee1.getFirstName() + " " + employee1.getLastName());
        System.out.println(employee1.getHomeAddress());

输出以下:

Junior Moore
151 Corner Street

Albany
NY 99999
US

咱们还能够经过调用有参构造器建立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>

这样,在IoC容器建立employee2实例时,Spring会调用有参的构造器,具体是哪一个构造器,由设置的constructor-arg肯定:

        Employee employee2 = context.getBean("employee2", Employee.class);
        System.out.println(employee2.getFirstName() + " " + employee2.getLastName());
        System.out.println(employee2.getHomeAddress());

输出以下:

Senior Moore
151 Corner Street

Albany
NY 99999
US

三、p名称空间方式依赖注入

四、spel方式依赖注入、

p名称空间方式依赖注入和spel方式依赖注入使用很少,所以不作介绍,有兴趣能够参考其余博客。

五、复杂类型注入

若是类中的字段存在复杂类型,如数组,集合(List,Set,Map),Properties,这时依赖注入的配置文件将会有一些小的变化,具体能够参考博客:Spring依赖注入之数组,集合(List,Set,Map),Properties的注入

注:本文所使用的程序来自控制反转和依赖注入的理解(通俗易懂),代码下载地址:https://github.com/pauldeck/springmvc-2ed

参考文献

[1]Spring框架下载方法

[2]Spring MVC学习指南

[3]控制反转和依赖注入的理解(通俗易懂)

[4]Spring MVC(推荐)

[5]Spring装配Bean---使用xml配置(推荐)

[6]Spring应用上下文中Bean的生命周期

相关文章
相关标签/搜索