SpringMVC 学习指南<一>

Spring框架

依赖注入技术,作为代码可测试性的一个解决方案已经被广泛应用,很多人在使用中并不区分依赖注入和控制反转(IOC)

简单来说,依赖注入的情况如下,有两个组件A和B,A依赖与B。假定A是一个类,且A有一个方法importantMethod使用到B,如下

public class A {
	public  void importantMethod(){
		B b = ...//get an instance of 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() {
		// no nedd to worry about creating b anymore
		// B b = ...//get an instance of B
		b.usefulMethod();
	}
	public void setB(B b) {
		this.b = b;
	}
}


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

当然,也可以采用构造器的方式注入,如下所示:

public class A {
	private B b;
	public A (B b){
		this.b=b;
	}
	public void importantMethod() {
		// no nedd to worry about creating b anymore
		// B b = ...//get an instance of B
		b.usefulMethod();
	}
}

本例中,Spring会先创建B的实例,在创建实例A,然后把B注入到实例A中。ps:Spring管理对象成为beans

通过提供一个控制反转容器(或者依赖注入容器),Spring为我们提供一种可以聪明的管理java对象依赖关系的方法。其优雅之处在于,我们了解Spring框架的存在,更不需要引入任何Spring类型。

从1.0版本开始,Spring就同时支持setter和构造器方式的依赖注入,从2.5版本开始,通过Autowired注解,Spring支持基于field方式和依赖注入,但缺点是程序必须引入org.springframework.beans.factory.annotation.Autowired,这对Spring产生了依赖,这样,程序无法直接迁移到另一个依赖注入容器间。

使用Spring,程序几乎将所有的重要对象的创建工作移交给Spring,并配置如何注入依赖。Spring支持XML或注解两种配置方式。此外,还需要创建一个ApplicationContext对象,代表一个Spring控制反转容器,org.springframework.context.ApplicationContext接口有多个实现,包裹ClassPathXmlApplicationContext和FileSystemXmlApplicationContext。这两个实现都需要至少一个包含beans信息的XML文件。ClassPathXmlApplictionContext尝试在类加载路径中加载配置文件,而FileSystemXmlApplicationContext则从文件系统中加载。下面从类路径中加载config1.xml和config2.xml的ApplicationContext创建一个代码示例。

	context = new ClassPathXmlApplicationContext(new String[]{"config1.xml","config2.xml"});
		//可以通过调用ApplicationContext的getBean方法获得对象。
		context.getBean("a",A.class);
		//getBean方法会查询id为a且类型那个为A的bean对象,
	
ps :理想情况下,我们仅需要在测试代码中创建一个ApplicationContext,应用程序本身无需处理。对于springmvc应用,可以通过一个SpringServlet来处理ApplicationContext,而无需直接处理

1.1 XML配置文件

从1.0版本开始,spring就支持基于xml的配置,从2.5版本开始,增加了通过注解的配置支持,配置文件的根元素通常为

<span style="font-size:14px;"><?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-3.2.xsd">

	。。。。。

</beans></span>
如果需要跟江的Spring配置能力,可以在schema location 属性中添加相应的schema。配置文件可以是一份,也可以分解为多份,已支持模块化配置,ApplictionContext的实现类支持读取多份配置文件。另一种选择是,通过一份主配置文 件,将该文件导入到其他的配置文件。下面是一个导入配置文件的示例。

<span style="font-size:14px;"><?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-3.2.xsd">

	<import resource="config.xml" />
	<import resource="module2/congif.xml" />
	<import resource="/resources/config3.xml" />

</beans></span>

1.2 Spring控制反转容器的使用

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

1.2.1通过构造器创建一个bean的实例

之前的方法中,可以通过调用ApolicationContext的getBean方法可以获取到一个bean的实例。下面的配置文件中定义了一个名为product的bean

<span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

	
	<!-- demo2 -->
	<bean name="product" class="cn.redis.model.Product"></bean>
	
</beans></span>
该bean的定义告诉Spring通过无参的构造来初始化product类。如果不存在该构造器(如果类作者重载了构造器,且没有显示声明默认构造器),则Spring将抛出一个异常。

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

public void test1(){
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"config1.xml"});
		Product product = context.getBean("Product",Product.class);
		product.setName("www");
		System.out.println("product:"+product.getName());
	}
1.2.2 通过工厂方法创建一个bean实例

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

<bean name = "calendar" class="java.util.Calendar"
 factory-method="getInstance"/>
本例中采用了id属性,而非name属性来标识Bean,采用了getBean方法来获取Calendar实例。

1.2.3 DestroyMethod的使用

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

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

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


1.2.4 向构造器传递参数

spring 支持通过带参数的构造器来初始化类

proudct类

public class Product implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;
	private String description;
	private float price;

	public Product() {
	}

	

	public Product(String name,String description,float price) {
<span style="white-space:pre">		</span>this.name=name;
<span style="white-space:pre">		</span>this.description = description;
<span style="white-space:pre">		</span>this.price=price;
<span style="white-space:pre">	</span>}


	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="cn.redis.model.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="cn.redis.model.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>
PS:采用这种方式,对应构造器的所有参数必须传递,缺一不可。


1.2.5 Setter 方式依赖注入

下面以employee类和address类为例,说明setter方式依赖注入。


package cn.redis.model;

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

	public Employee() {
	}

	public Employee(String firstName, String lastName, Address homeAddress) {
		super();
		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 "Employee [firstName=" + firstName + ", lastName=" + lastName
				+ ", homeAddress=" + homeAddress + "]";
	}

}

package cn.redis.model;

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

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

	// getters and setters onitted

	@Override
	public String toString() {
		return "Address [line1=" + line1 + ", city=" + city + ", state="
				+ state + ", zipCode=" + zipCode + ", country=" + country + "]";
	}

}
Employee 依赖于Address类,可以通过如下配置来保证每一个Employee实例都能包含Address类
<bean name="simpleAddress" class="cn.redis.model.Address">
		<constructor-arg name="line1" value="151 corner" />
		<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="employee" class="cn.redis.model.Employee">
		<constructor-arg name="firstName" ref="simpleAddress" />
		<constructor-arg name="lastName" value="Junio" />
		<constructor-arg name=" homeAddress " value="Moore" />
	</bean>
simpleAddress 对象是Address类的一个实例,其通过构造器方式实例化。employee对象则通过配置property元素来调用setter方法设置值,需要注意的是,homeAddress属性配置是simpleAddress对象的引用。

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

1.2.6 构造器方式的依赖注入

我们还可以将Address对象通过构造器注入,如下所示

<bean name="employee2" class="cn.redis.model.Employee">
		<constructor-arg name="homeAddress"  ref="simpleAddress"/>
		<constructor-arg name="firstName"  value="w"/>
		<constructor-arg name="lastName"  value="qq"/>
	</bean>

<bean name="simpleAddress" class="cn.redis.model.Address">
		<constructor-arg name="line1" value="151 corner" />
		<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>
1.3小结

主要学习了依赖注入的概念以及基于Spring容器的实践,后续将再次基础上配置Spring应用。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值