在此声明:本文摘自csdn的博客 javamxj 的文章,我觉得这篇文章写得太经典了,所以放在自己的blog上收藏起来,以便学习之用。在此感谢javamxj,大家也可以直接访问javamxj的blog(http://blog.csdn.net/javamxj)
1.收集的一些资料
“好的开始是成功的一半”,但凡一种新的技术,开始阶段一般是很苦恼的。为了不让更多的人走同样的弯路,我这里就把学习Spring的经验与大家分享, 一起快乐一下。
Spring是什么?反正这里我不会谈论春天的。我要说的是Spring Framework ,它又是用来做什么的呢?一会半会我也说不清楚。还好现在是互联网的时代,google一下,会发现不少有用的东西。
Spring版本。
Spring的下载包有两种,一种是带有“with-dependencies”名称的,这种包含了Spring常用到的第三方包,比如Hibernate、aopalliance、jakarta-commons等。这里就使用了这种包,可以省却查找第三方包的麻烦。
解压这个包,可以在 docs\reference目录下找到Spring 的参考手册,有html和pdf两种格式。如果你的英文不太好,可以看看Spring中文论坛翻译的1.1版本的中文版(pdf格式)。这个参考手册就是入门的不二法宝。
● 新手刚学Spring时,可能对一些概念似懂非懂,比如IoC(这里可不是国际奥委会)、DI等。这里向你推荐几篇好文章,有助于理解Spring。
· Robert C Martin, Bob: The Dependency Inversion Principle
● 如果要系统的学习Spring,还是需要Book的。
看看作者是谁,就知道这本书的质量如何了。毫无疑问,这本书吹响了向Spring进军的号角。前半部分主要阐述了J2EE开发的方方面面的经验和设计,后半部分通过对J2EE的改善设计而引申出了SpringFramework。这本书的中译本也出来了,不过翻译的一般。
看看书名就会吓一跳,不过Rod Johnson完全有资格说出来。前半本介绍EJB的不足,后半本讲Spring的原理。这本书的中译本也出来了。
这本书主要阐述了如何利用Java进行轻量级开发,有关Spring的内容比较少,只有一章,不过此书获得了Jolt 大奖,质量肯定没的说了。
Manning出版的“in action”系列图书,质量一直非常好。此书系统介绍了Spring的方方面面,解析相当清晰。
这本是source beat的电子书(只出电子版)。如果要深入这本书,需要有相当的基础。这本书非常适合有实践项目经验的人。采用TDD的方式使用Spring,而且提供Spring整合其他framework的各种作法 (相当多)。同时作者也维护着一个开源的项目appfuse。
我目前只看过了样章,还很不错,很系统,也很细致,尤其书中提供的源代码很适合新手练习。
预计2005年7月出版,作者阵容挺庞大的,几乎都是Spring开发团队的,值得期待。
这好像是目前为止系统介绍Spring的唯一简体中文书籍。
以上书籍都在网上提供了书中的源代码下载和部分样章,如果拿不到书,看看源代码也是很不错。
● 说完书籍,再介绍一些好的论坛。
在其右上方的搜索栏中填入“spring”,可以获得不少整理好的有关spring的资料。
好了,先写到这里了,以后会陆续添加一些好的资料和站点。
2.HelloWorld(1)
这篇文章主要谈谈Spring的入门开发,例子很简单,就是输出一条语句。有关各种软件的配置这里就不在多说了,如有不明白的,可以参考我以前的文章。
1. 所需软件
· JDK 5.0
如果安装后在Eclipse中看不到XmlBuddy,那么在eclipse命令后加上“-clean”参数。
2. 配置
● 配置Eclipse:
· Window->Perferences->Java->Compiler:将"Compiler compliance level"设为“5.0”
· Window->Perferences->Java->Build Path:勾选“Folders”
● 建立库文件夹
这里先将spring-framework-1.2.1-with-dependencies.zip解压,将其中的spring.jar(dist目录中)、commons-logging.jar(lib\jakarta-commons目录)、log4j-1.2.9.jar(lib\log4j目录)这三个文件复制到的”D:\java\Spring\lib" 目录中,然后在Eclipse中建立一个“Spring”库,将那三个文件添加进“Spring”库中。
1. 创建项目
· 新建一个Java Project:SpringHello,注意要导入用户库Spring。
· 这是完成后整个项目的结构(预览一下):
2. 简单的HelloWorld
·下面开始创建一个新类:HelloWorld ;包名:javamxj.spring.beginning1,代码如下:
HelloWorld.java |
package javamxj.spring.beginning1;
public class HelloWorld { public static void main(String[] args) {
System.out.println("Hello World!"); } } |
OK!非常简单,我就是要它打印出一条语句“Hello World!”。
现在我不想输出“Hello World!”,我想随心所欲的输出任何语句,很简单啊!将“Hello World!”替换成所希望输出的语句即可。不过这样有一个缺点,每次修改好了,都需要重新编译一下程序。像这样的小程序固然无所谓,可是如果是一个大项目,这样做就有些讨厌了。
还好,只要稍微修改一下程序,通过参数输入即可。
· 继续在这个包下建立一个新类:HelloWorldWithCommandLine,同样非常简单:
HelloWorldWithCommandLine.java |
package javamxj.spring.beginning1;
public class HelloWorldWithCommandLine {
public static void main(String[] args) { if (args.length > 0) { System.out.println(args[0]); } else { System.out.println("Hello World!"); } } } |
· 选中HelloWorldWithCommandLine,右击->Run As->Run...,在弹出窗口切换到“Arguments”栏,在“program arguments”中填入“Hello,javamxj!”,如下图:
这样,就输出了我希望的语句。
第一部分到此,请继续看第二部分。
2.HelloWorld(2)
这是第二部分。
3. 采用“工厂模式”
· 新建一个包,包名:javamxj.spring.beginning2,在这个包下,新建一个“Hello”接口,这个接口含有一个方法。
Hello.java |
package javamxj.spring.beginning2;
public interface Hello { void sayHello(); } |
· 分别新建两个类,实现这个接口。
HelloWorld.java |
package javamxj.spring.beginning2;
public class HelloWorld implements Hello {
public void sayHello() { System.out.println("Hello World!"); } } |
HelloJavamxj.java |
package javamxj.spring.beginning2;
public class HelloJavamxj implements Hello {
public void sayHello() { System.out.println("Hello, javamxj!"); } } |
· 建立一个工厂类,调用上面两个实现接口的子类。
HelloFactory.java |
package javamxj.spring.beginning2;
public class HelloFactory {
public Hello getHello(String hello) {
if (hello.equals("world")) return new HelloWorld(); else if (hello.equals("javamxj")) return new HelloJavamxj(); else throw new IllegalArgumentException("输入参数错误!"); } } |
· 最后,利用工厂类,测试一下。
Test.java |
package javamxj.spring.beginning2;
public class Test { public static void main(String[] args) {
Hello hello = null; HelloFactory factory = new HelloFactory();
hello = factory.getHello("world"); hello.sayHello();
hello = factory.getHello("javamxj"); hello.sayHello(); } } |
运行Test,控制台输出如下语句:
Hello World!
Hello, javamxj!
4. Setter Injection
讲了这么多,似乎一点都不关Spring的事,别急,下面就看看用Spring是如何实现的。
· 新建一个包,包名:javamxj.spring.beginning3
· 在这个包下,新建一个HelloBean的类,这个类有一个属性:helloWorld属性,这个属性只是一个字符串。可以通过setHelloWorld方法设置这个属性,getHelloWorld方法得到这个属性。
HelloBean.java |
package javamxj.spring.beginning3;
public class HelloBean {
private String helloWorld = "Hello!World!";
public void setHelloWorld(String helloWorld) { this.helloWorld = helloWorld; }
public String getHelloWorld() { return helloWorld; }
} |
· 同样,在这个包下,建立一个XML文件,它是Spring配置文件。
bean.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="helloBean" class="javamxj.spring.beginning3.HelloBean"> <property name="helloWorld"> <value>Hello! Javamxj!< SPAN>value> < SPAN>property> < SPAN>bean> < SPAN>beans> |
Spring配置文件必须遵循spring-beans.dtd定义的内容模型。
这个XML文件在Spring容器中声明了一个HelloBean的实例,并且将它的helloWorld属性设置为“Hello! Javamxj!”。
分析这个XML文件,位于根部的是元素,它是任何Spring配置文件的根元素。元素用于告诉Spring容器一个类以及它是如何配置的。这里,id属性用于为Bean helloBean命名,而class属性指定了这个Bean的全限定类名。
在
元素内,元素用于设置一个属性,在本例中它是helloWorld属性。通过使用,我们告诉Spring容器当设置这个属性时调用setHelloWorld方法。greeting属性的值定义在元素内。在这里我设置为“Hello! Javamxj!”。
bean.xml必须在您的CLASSPATH可以存取到的目录中。
· 新建Main.java,测试一下。
Main.java |
package javamxj.spring.beginning3;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class Main { public static void main(String[] args) {
// 直接调用HelloBean HelloBean helloBean = new HelloBean(); System.out.println(helloBean.getHelloWorld());
// 利用Spring调用HelloBean Resource res = new ClassPathResource("javamxj/spring/beginning3/bean.xml"); BeanFactory factory = new XmlBeanFactory(res);
helloBean = (HelloBean) factory.getBean("helloBean"); System.out.println(helloBean.getHelloWorld()); } } |
这里使用的BeanFactory类就是Spring容器。在将hello.xml文件装入容器后,main方法调用BeanFactory的getBean方法检索出了helloBean服务的一个引用。通过这个引用,它调用了getHelloWorld方法。当我们运行这个Hello应用时,它会打印出“Hello! Javamxj!”。
· 另外,为了更好的调试程序,了解运行机理,建立一个log4j.properties,放在src目录下。
src/log4j.properties |
log4j.rootLogger=warn, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%c{1} - %m%n |
5. Constructor Injection
· 新建一个包,包名:javamxj.spring.beginning3
· 新建一个HelloBean.java文件,可以与Setter Injection中的HelloBean比较一下,注意是通过Constructor设置helloWorld属性值的。
HelloBean.java |
package javamxj.spring.beginning4;
public class HelloBean {
private String helloWorld;
public HelloBean(String helloWorld) { this.helloWorld = helloWorld; }
public void sayHello() { System.out.println(helloWorld); } } |
· 同样,在这个包下,也需要一个Spring配置文件。
bean.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="helloBean" class="javamxj.spring.beginning4.HelloBean"> <constructor-arg> <value>Hello! Javamxj!< SPAN>value> < SPAN>constructor-arg> < SPAN>bean> < SPAN>beans> |
这里通过来表示将使用 constructor injection。如果constructor的参数不只一个,那么需要利用index属性指定参数的位置索引,即,索引值从0开始。
· 测试一下。
Main.java |
package javamxj.spring.beginning4;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class Main { public static void main(String[] args) {
Resource res = new ClassPathResource("javamxj/spring/beginning4/bean.xml"); BeanFactory factory = new XmlBeanFactory(res);
HelloBean helloBean = (HelloBean) factory.getBean("helloBean"); helloBean.sayHello(); } } |
这样,通过BeanFactory的getBean方法,以及xml配置文件,避免了在Main类中直接实例化HelloBean,消除了应用程序(Main)与服务(HelloBean)之间的耦合,实现了IOC(控制反转)或者说实现了依赖的注射(Dependency Injection)。
3. 加载Bean的配置文件
1. 创建项目
· 新建一个Java Project:SpringBeanFile,注意要导入用户库Spring。
· 这是完成后整个项目的结构(预览一下):
2. 编写类文件
· 下面开始创建一个新类:BeanFile ;包名:javamxj.spring.beanfile
BeanFile.java |
package javamxj.spring.beanfile;
public class BeanFile {
private String beanFile = "多种方式加载Bean的配置文件";
public void setBeanFile(String beanFile) { this.beanFile = beanFile; }
public String getBeanFile() { return beanFile; } } |
· 新建Test.java,测试一下。
package javamxj.spring.beanfile;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
public class Test {
public static void main(String[] args) {
// 直接调用HelloBean
BeanFile bf = new BeanFile();
System.out.println(bf.getBeanFile());
/**
* 利用XmlBeanFactory(Resource resource)
* 这里Resource必须是xml格式
* Resource包括:AbstractResource, ClassPathResource, FileSystemResource,
* InputStreamResource, ServletContextResource, UrlResource
*/
/*
* 利用 InputStreamResource(InputStream inputStream)
* 要将bean.xml放在项目根目录下
*/
InputStream is = null;
try {
is = new FileInputStream("bean1.xml");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Resource resource = new InputStreamResource(is);
sayHello(resource);
/*
* 利用 ClassPathResource(String path)
* 要将bean.xml放在源文件夹(src)目录下
*/
resource = new ClassPathResource("bean2.xml");
sayHello(resource);
/*
* 利用 FileSystemResource(String path)
* 要将bean.xml放在项目根目录下
*/
resource = new FileSystemResource("bean3.xml");
sayHello(resource);
/*
* 利用 Properties
* 要将bean.properties放在类路径--源文件夹(src)目录下
*/
BeanDefinitionRegistry reg = new DefaultListableBeanFactory();
PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(
reg);
reader.loadBeanDefinitions(new ClassPathResource("bean.properties"));
BeanFactory factory = (BeanFactory) reg;
bf = (BeanFile) factory.getBean("beanFile");
System.out.println("利用 " + bf.getBeanFile() + " 加载 Bean.properties");
/*
* 利用 ApplicationContext
* 要将bean.xml放在类路径--源文件夹(src)目录下
*/
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"bean4.xml");
bf = (BeanFile) appContext.getBean("beanFile");
System.out.println("利用 " + bf.getBeanFile() + " 加载 Bean.xml");
}
public static void sayHello(Resource resource) {
BeanFactory factory = new XmlBeanFactory(resource);
BeanFile bf = (BeanFile) factory.getBean("beanFile");
System.out.println("利用 " + bf.getBeanFile() + " 加载 Bean.xml");
}
}
3. 配置文件
由上面的Test.java可知,这里一共需要四个XML文件和一个Properties文件,现在分别建立。
· bean1.xml放在项目根目录下:
bean1.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="beanFile" class="javamxj.spring.beanfile.BeanFile"> <property name="beanFile"> <value>InputStreamResource(InputStream inputStream)< SPAN>value> < SPAN>property> < SPAN>bean> < SPAN>beans> |
bean2.xml、bean3.xml、bean4.xml与bean1.xml相似,仅仅需要替换一下值即可。重要的注意文件的存放位置。这里只给出不同的代码;
· bean2.xml放在源文件夹(src)目录下:
bean2.xml(部分) |
<property name="beanFile"> <value>ClassPathResource(String path)< SPAN>value> < SPAN>property> |
· bean3.xml放在项目根目录下:
bean3.xml(部分) |
<property name="beanFile"> <value>FileSystemResource(String path)< SPAN>value> < SPAN>property> |
· bean4.xml放在源文件夹(src)目录下:
bean4.xml(部分) |
<property name="beanFile"> <value>ApplicationContext< SPAN>value> < SPAN>property> |
Spring也可以使用属性文件来定义配置文件,如下:
· bean.properties放在源文件夹(src)目录下:
bean.properties |
beanFile.class=javamxj.spring.beanfile.BeanFile beanFile.beanFile=properties |
4. 运行程序
右击Test.java,运行程序,控制台输出如下:
多种方式加载Bean的配置文件
利用 InputStreamResource(InputStream inputStream) 加载 Bean.xml
利用 ClassPathResource(String path) 加载 Bean.xml
利用 FileSystemResource(String path) 加载 Bean.xml
利用 properties 加载 Bean.properties
利用 ApplicationContext 加载 Bean.xml
5. 小结
这篇文章主要谈论了如何加载Spring的配置文件,一般来说,就是BeanFactory和ApplicationContext。最常使用的、简单的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory,其加载方式为:
BeanFactory factory = new XmlBeanFactory(Resource resource)
这里resource必须是xml格式。Resource包括: AbstractResource, ClassPathResource, FileSystemResource, InputStreamResource, ServletContextResource, UrlResource。这篇文章 谈了常用的三种:ClassPathResource, FileSystemResource, InputStreamResource。
ApplicationContext包括了BeanFactory的所有功能,也要比BeanFactory强大的多(以后会详细介绍的)。这里只简单的使用了ClassPathXmlApplicationContext加载了Bean配置文件。你可以将log4j.properties中的“Warn”改为“Debug”, 对比一下和ClassPathResource的输出,
在Eclipse中,bean2.xml、bean4xml虽然都是放在源文件夹(src)目录下,但实际上,是由已经编译好的Test.class从类文件夹(这里是bin文件夹)中加载的。
4.安装和使用SpringIDE
这篇文章谈谈如何安装与使用SpringIDE。作为辅助Spring开发的工具,SpringIDE还是比较有用的。
● 软件配置:
· Eclipse 3.1
· SpringIDE
● 安装:
· 解压安装GEF3.1,
· 在eclipe中打开 Help ->Software Updates ->Find and install,选择
Search for new features to install. 在打开的界面中,选择new archived site,选择下载的zip文件(如果没有下载这个zip文件,也可以选择New Remote Site,直接从网上更新),再选择一个安装的目录就可以了.
点击Next,在出现的对话框中勾选“updatesite_1.2.1.zip”,然后一直点击Next,直到安装完成。
● 使用:
· 右击SpringHello,在弹出菜单中选择“Add Spring Project Nature”,如下图:
如果成功,则这时该项目就会在右上角挂上了“S”.
· 右键项目名,查看其properties,选择“Spring Beans”,切换到“Config Files”,点击“Add”,将包javamxj.spring.beginning3下的bean.xml加入到其中。
· 这时可以看到bean.xml和HelloBean.java的右上角都挂上了“S”。
这是由于SpringIDE分析加载的bean.xml文件,找到了“helloBean”指向的类HelloBean.java。如果找不到这个文件,则会显示一个错误,指明这个类找不到;如果将“helloBean”指向了包javamxj.spring.beginning4下的bean.xml,虽然这个类存在,但由于属性不匹配,同样会显示出错误。这样就验证了XML的配置,可以提前知道配置中的错误。
· Spring Beans view
选中bean.xml,切换到“Navigate” ,如图:
· 显示图表,如图:

5.Bean的标志符(id与name)
又重新学习了Spring,想把自己的心得写下来,感觉有些无从下手。想来想去,还是根据Spring中文论坛翻译的《Spring Framework 开发参考手册》(1.1版本的中文版,pdf格式),来组织自己的思路。在这个阶段,我发布的关于Spring的文章,基本上都是入门级别的。相对而言,对于新手的帮助应该会更大。
虽然当前Spring的版本已经是1.2.2了,但同1.1版本的中文版相比,spring-reference还是相差不大的(尤其是前面几章的基础部分),所以采用的还是1.1版本的开发参考手册。
这个系列的文章,我准备根据开发参考手册的讲解,有针对性的增加大量的比较简单的实例,每个实例尽量只解释一个问题。下面就从3.2.4小节——《Bean的标志符(id与name)》讲起。
一般来说,在一个XmlBeanFactory中,定义一个bean时,采用的是的样式,如。
这里id的命名格式必须符合XML ID属性的命名规范,例如,不能以数字开头,“222”就不是合法的id值。为了解决这个问题,可以使用name属性指定一个和多个id(用逗号或者分号隔离)。
这里还是以HelloBean为例,这三个文件都放在包javamxj.spring.basic.aliases下。
· HelloBean
HelloBean.java |
package javamxj.spring.basic.aliases;
public class HelloBean {
private String helloWorld = "Hello!World!";
public void setHelloWorld(String helloWorld) { this.helloWorld = helloWorld; }
public String getHelloWorld() { return helloWorld; }
} |
· 配置文件
bean.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="helloBean" name="2hello,javamj@yahoo.com.cn" class="javamxj.spring.basic.aliases.HelloBean"> <property name="helloWorld"> <value>Hello! Javamxj!< SPAN>value> < SPAN>property> < SPAN>bean> < SPAN>beans> |
· 测试程序:
Main.java |
package javamxj.spring.basic.aliases;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class Main { public static void main(String[] args) {
Resource res = new ClassPathResource( "javamxj/spring/basic/aliases/bean.xml"); BeanFactory factory = new XmlBeanFactory(res);
HelloBean helloBean = (HelloBean) factory.getBean("helloBean"); HelloBean helloBean2 = (HelloBean) factory.getBean("2hello"); HelloBean helloBean3 = (HelloBean) factory.getBean("javamj@yahoo.com.cn");
System.out.println(helloBean.getHelloWorld());
// 验证是否指向同一个Bean System.out.println((helloBean == helloBean2)); System.out.println((helloBean == helloBean3));
// 输出这个Bean的别名 String[] aliases = factory.getAliases("helloBean"); for (String str : aliases) { System.out.println(str); } } } |
可以看出,使用中id属性和name属性几乎没有任何区别。
调用BeanFactory.getAliases(String)的方法时,传入的参数可以是任意一个Bean名字,输出的别名则是除去id之外的所有Bean名,如果没有指定id,则将其name属性中的第一个值指定为id。
当然,Bean的name属性不仅仅只是为了输入id属性所不允许的名字,它还有其它的用处,在后面的文章中会提及的。
6. Singleton的使用与否
上篇文章已经谈了《Spring Framework 开发参考手册》的3.2.4小节——《Bean的标志符(id与name)》,现在继续3.2.5小节——《Singleton的使用与否》。
文档已经把Singleton说的很清楚了,这里也不废话了。主要是了解在Spring中,默认的部署方式是Singleton,没有特别需要的话,一般使用Singleton。
这里还是以HelloBean为例,这三个文件都放在包javamxj.spring.basic.singleton下。
· HelloBean
这里多加了属性i,用它得到随机数。
HelloBean.java |
package javamxj.spring.basic.singleton;
public class HelloBean {
private String helloWorld;
private int i = (int) (100 * Math.random());
public HelloBean(String helloWorld) { this.helloWorld = helloWorld; }
public void sayHello() { System.out.println(helloWorld); System.out.println("输出随机整数: " + i); } } |
· 配置文件
在这个Beans中,定义了两个bean,都指向HelloBean类,主要不同就是第二个bean指明了singleton="false",即不采用singleton部署方式。
bean.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="singletonBean" class="javamxj.spring.basic.singleton.HelloBean"> <constructor-arg> <value>Hello! 这是singletonBean!< SPAN>value> < SPAN>constructor-arg> < SPAN>bean>
<bean id="prototypeBean" class="javamxj.spring.basic.singleton.HelloBean" singleton="false"> <constructor-arg> <value>Hello! 这是prototypeBean! < SPAN>value> < SPAN>constructor-arg> < SPAN>bean>
< SPAN>beans> |
· 测试程序:
分别取得singletonBean和prototypeBean各两个实例,然后输出随机数,最后比较同一个bean的两个实例的引用是否相同。
Main.java |
package javamxj.spring.basic.singleton;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class Main { public static void main(String[] args) {
Resource res = new ClassPathResource("javamxj/spring/basic/singleton/bean.xml"); BeanFactory factory = new XmlBeanFactory(res);
HelloBean h1 = (HelloBean) factory.getBean("singletonBean"); h1.sayHello(); HelloBean h2 = (HelloBean) factory.getBean("singletonBean"); h2.sayHello(); System.out.println("h1==h2: " + (h1==h2)); System.out.println(""); HelloBean h3 = (HelloBean) factory.getBean("prototypeBean"); h3.sayHello(); HelloBean h4 = (HelloBean) factory.getBean("prototypeBean"); h4.sayHello(); System.out.println("h3==h4: " + (h3==h4)); } } |
·运行,控制台输出:
Hello! 这是singletonBean!
输出随机整数: 7
Hello! 这是singletonBean!
输出随机整数: 7
h1==h2: true
Hello! 这是prototypeBean!
输出随机整数: 95
Hello! 这是prototypeBean!
输出随机整数: 60
h3==h4: false
7. ref的用法
ref元素是用在property中,来设置需要引用的容器管理的其它Bean。
它的用法:[,这里主要分析一下这三个参数的作用。]
这次先看实例,再进行讲解。
· 先建立一个包:javamxj.spring.basic.ref ,然后把以下5个文件放在这个包下。
HelloBean.java |
package javamxj.spring.basic.ref;
public class HelloBean { private String hello;
public String getHello() { return hello; }
public void setHello(String hello) { this.hello = hello; }
}
|
HelloDate.java |
package javamxj.spring.basic.ref;
import java.util.Date;
public class HelloDate { private Date date;
private HelloBean hb;
public void setDate(Date date) { this.date = date; }
public void setHb(HelloBean hb) { this.hb = hb; }
public void sayHello() { System.out.println(hb.getHello() + " " + date.toLocaleString()); }
} |
xml version="1.0" encoding="GBK"?>
DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="helloBean" class="javamxj.spring.basic.ref.HelloBean">
<property name="hello" value="Hello! Child Bean." />
< SPAN>bean>
<bean id="dateBean" name="#date" class="java.util.Date"/>
<bean id="hd1" class="javamxj.spring.basic.ref.HelloDate">
<property name="hb">
<ref bean="helloBeanParent"/>
< SPAN>property>
<property name="date">
<ref bean="#date"/>
< SPAN>property>
< SPAN>bean>
<bean id="hd2" class="javamxj.spring.basic.ref.HelloDate">
<property name="hb">
<ref local="helloBean"/>
< SPAN>property>
<property name="date">
<ref local="dateBean"/>
< SPAN>property>
< SPAN>bean>
<bean id="hd3" class="javamxj.spring.basic.ref.HelloDate">
<property name="hb">
<ref parent="helloBean"/>
< SPAN>property>
<property name="date">
<bean class="java.util.Date"/>
< SPAN>property>
< SPAN>bean>
< SPAN>beans>
parent.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="helloBean" class="javamxj.spring.basic.ref.HelloBean"> <property name="hello" value="Hello! Javamxj." /> < SPAN>bean> <bean id="helloBeanParent" class="javamxj.spring.basic.ref.HelloBean"> <property name="hello" value="Hello! Parent Bean." /> < SPAN>bean> < SPAN>beans> |
Main.java |
package javamxj.spring.basic.ref;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource;
public class Main {
public static void main(String[] args) { BeanFactory parent = new XmlBeanFactory(new ClassPathResource( "javamxj/spring/basic/ref/parent.xml")); BeanFactory child = new XmlBeanFactory(new ClassPathResource( "javamxj/spring/basic/ref/beans.xml"), parent);
HelloDate hd1 = (HelloDate) child.getBean("hd1"); HelloDate hd2 = (HelloDate) child.getBean("hd2"); HelloDate hd3 = (HelloDate) child.getBean("hd3");
hd1.sayHello(); hd2.sayHello(); hd3.sayHello(); } } |
·运行Main.java,输出结果如下:
Hello! Parent Bean. 2005-8-10 22:25:56
Hello! Child Bean. 2005-8-10 22:25:56
Hello! Javamxj. 2005-8-10 22:25:56
OK!这里主要分析beans.xml、Main.java这两个文件。对于Main.java要注意的是如何加载“parent”的,重点看看beans.xml中ref元素的用法。
首先定义两个bean:helloBean、dateBean,分别指向HelloBean类和Date类。然后定义了hd1、hd2、hd3等三个bean,都指向HelloDate类。
·hd1:
property标签中的“helloBeanParent”并不存在于beans.xml中,而是在parent.xml中,使用[可以从其它bean配置文件中寻找需要加载的目标bean。bean属性的值可以同目标bean的id属性相同,也可以同它的name属性中任意的一个值相同。]
·hd2:
property标签中的“helloBean”如果不存在于beans.xml中,则XML解析器会提示错误。[只能这个bean配置文件中寻找需要加载的目标bean,而且local属性值必须同目标bean的id属性相同。]
·hd3:
property标签中的“helloBean”同时存在于beans.xml和parent.xml中,使用[则会优先从beans.xml中寻找需要加载的目标bean,如果需要从parent.xml中加载目标bean,则需使用][。在设置date时,使用的是内联bean,这时可以不要任何id或name定义。]
8.集合对象注入
这篇文章来谈谈《Spring Framework 开发参考手册》的3.3.2小节中的集合对象注入。
在项目开发中,还是经常会用到集合对象注入的,不过感觉没有多少需要介绍的,这次就只给出实例了。
· 先建立一个包:javamxj.spring.basic.collections ,然后把以下4个文件放在这个包下。
Hello.java |
package javamxj.spring.basic.collections;
public class Hello { public String toString() { return "这是一个bean"; } } |
package javamxj.spring.basic.collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class CollectionInjection {
private Map someMap;
private Properties someProps;
private Set someSet;
private List someList;
public void setSomeProps(Properties someProps) {
this.someProps = someProps;
}
public void setSomeList(List someList) {
this.someList = someList;
}
public void setSomeMap(Map someMap) {
this.someMap = someMap;
}
public void setSomeSet(Set someSet) {
this.someSet = someSet;
}
public void displayInfo() {
System.out.println("Map contents:");
for (Object key : someMap.keySet()) {
System.out.println("Key: " + key + " - Value: " + someMap.get(key));
}
System.out.println("\nProperties contents:");
for (Object key : someProps.keySet()) {
System.out.println("Key: " + key + " - Value: "
+ someProps.get(key));
}
System.out.println("\nSet contents:");
for (Object i : someSet) {
System.out.println("Value: " + i);
}
System.out.println("\nList contents:");
for (Object i : someList) {
System.out.println("Value: " + i);
}
}
}
xml version="1.0" encoding="GBK"?>
DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="hello" class="javamxj.spring.basic.collections.Hello"/>
<bean id="injectCollection"
class="javamxj.spring.basic.collections.CollectionInjection">
<property name="someMap">
<map>
<entry key="someValue" value="Hello javamxj!"/>
<entry key="someBean">
<ref local="hello"/>
< SPAN>entry>
< SPAN>map>
< SPAN>property>
<property name="someProps">
<props>
<prop key="姓">张< SPAN>prop>
<prop key="名">小小< SPAN>prop>
< SPAN>props>
< SPAN>property>
<property name="someSet">
<set>
<value>Hello World!< SPAN>value>
<ref local="hello"/>
< SPAN>set>
< SPAN>property>
<property name="someList">
<list>
<value>Hello World!< SPAN>value>
<ref local="hello"/>
< SPAN>list>
< SPAN>property>
< SPAN>bean>
< SPAN>beans>
Main.java |
package javamxj.spring.basic.collections;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource;
public class Main { public static void main(String[] args) { BeanFactory bf= new XmlBeanFactory(new ClassPathResource( "javamxj/spring/basic/collections/beans.xml"));
CollectionInjection c = (CollectionInjection)bf.getBean("injectCollection"); c.displayInfo(); } } |
·运行Main.java,输出结果如下:
Map contents:
Key: someValue - Value: Hello javamxj!
Key: someBean - Value: 这是一个bean
Properties contents:
Key: 姓 - Value: 张
Key: 名 - Value: 小小
Set contents:
Value: Hello World!
Value: 这是一个bean
List contents:
Value: Hello World!
Value: 这是一个bean
9. Lookup方法注入
这篇文章来谈谈《Spring Framework 开发参考手册》的3.3.3.1小节中的Lookup方法注入。
仔细看看文档,这种方法主要是用在Singleton的Object中使用非Singleton的Bean时,通过lookup-method的那个方法来取得非Singleton的Bean。一般用的不多,在用这种定义之前最好想明白你的需求。
· 先建立一个包:javamxj.spring.basic.lookup ,然后把以下5个文件放在这个包下。
Hello.java. |
package javamxj.spring.basic.lookup;
public interface Hello { public Random getRandom(); public abstract Random createRandom(); } |
|
package javamxj.spring.basic.lookup;
public class Random { private int i = (int) (100 * Math.random());
public void printRandom() { System.out.println("输出随机整数: " + i); } } |
HelloAbstract.java |
package javamxj.spring.basic.lookup;
public abstract class HelloAbstract implements Hello { private Random random;
public Random getRandom() { return random; }
public void setRandom(Random random) { this.random = random; }
public abstract Random createRandom(); } |
beans.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="ran" class="javamxj.spring.basic.lookup.Random" singleton="false"/> <bean id="hello" class="javamxj.spring.basic.lookup.HelloAbstract"> <lookup-method name="createRandom" bean="ran"/> <property name="random"> <ref local="ran"/> < SPAN>property> < SPAN>bean> < SPAN>beans> |
package javamxj.spring.basic.lookup;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class Main {
public static void main(String[] args) {
Resource res = new ClassPathResource( "javamxj/spring/basic/lookup/beans.xml");
BeanFactory ft = new XmlBeanFactory(res);
Hello h = (Hello) ft.getBean("hello");
Random r1 = h.getRandom();
Random r2 = h.getRandom();
System.out.println("没有采用Lookup方法注入:");
System.out.println("Random 的两个实例指向同一个引用:" + (r1 == r2));
r1.printRandom();
r2.printRandom();
Random r3 = h.createRandom();
Random r4 = h.createRandom();
System.out.println("\n采用Lookup方法注入:");
System.out.println("Random 的两个实例指向同一个引用:" + (r3 == r4));
r3.printRandom();
r4.printRandom();
}
}
简单说明一下:
· Hello是一个接口类,实现面向接口编程。
· Random类用来输出随机整数。
· HelloAbstract是一个抽象类,包含了一个属性:random,还包含一个抽象方法createRandom(),如果这个方法不是抽象的,spring会重写已有的实现。
· beans.xml中定义了两个bean,ran指向Rondom类,注意它不是singleton的;hello指向HelloAbstract类,其中的random属性指向ran,createRandom方法也指向ran。
· 在Main类中,Hello类分别利用getRandom()和createRandom()方法来调用Random类。
· 这次需要将 spring-framework主目录\lib\cglib 目录中的cglib-nodep-2.1_2.jar加入到项目的 Libraries中,使用其中的动态代理。
运行结果:
没有采用Lookup方法注入:
Random 的两个实例指向同一个引用:true
输出随机整数: 98
输出随机整数: 98
采用Lookup方法注入:
Random 的两个实例指向同一个引用:false
输出随机整数: 51
输出随机整数: 26
10. 任意方法的替换
这篇文章来谈谈《Spring Framework 开发参考手册》的3.3.3.2小节中的“任意方法的替换”。
· 先建立一个包:javamxj.spring.basic.MethodReplacer ,然后把以下5个文件放在这个包下。
Hello.java |
package javamxj.spring.basic.MethodReplacer;
public interface Hello { public void sayHello(String s); } |
HelloImpl.java |
package javamxj.spring.basic.MethodReplacer;
public class HelloImpl implements Hello { public void sayHello(String name) { System.out.println("Hello: " + name); } } |
HelloReplacer.java |
package javamxj.spring.basic.MethodReplacer;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;
public class HelloReplacer implements MethodReplacer { public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
System.out.println("你好: " + args[0]); return null; } } |
beans.xml |
xml version="1.0" encoding="GBK"?> DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="helloReplacer" class="javamxj.spring.basic.MethodReplacer.HelloReplacer"/> <bean id="helloA" class="javamxj.spring.basic.MethodReplacer.HelloImpl"/> <bean id="helloB" class="javamxj.spring.basic.MethodReplacer.HelloImpl"> <replaced-method name="sayHello" replacer="helloReplacer"/> < SPAN>bean> < SPAN>beans> |
Main.java |
package javamxj.spring.basic.MethodReplacer;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource;
public class Main { public static void main(String[] args) { Resource res = new ClassPathResource( "javamxj/spring/basic/MethodReplacer/beans.xml"); BeanFactory ft = new XmlBeanFactory(res);
// 没有使用replaced-method Hello h = (Hello) ft.getBean("helloA"); h.sayHello("分享Java快乐"); // 使用replaced-method h=(Hello) ft.getBean("helloB"); h.sayHello("分享Java快乐");
} } |
简单说明一下:
· Hello是一个接口类,实现面向接口编程。
· HelloImpl类实现了Hello接口,简单的输出一个语句。
· HelloReplacer类要实现MethodReplacer接口,reimplement中提供替换后的方法。
· beans.xml中定义了三个bean,helloReplacer指向HelloReplacer类;helloA和helloB都指向HelloImpl类,其中helloB中定义了replaced-method。
· 在Main类中,对比输出使用replaced-method前后的语句。
· 这次需要将 spring-framework主目录\lib\cglib 目录中的cglib-nodep-2.1_2.jar加入到项目的 Libraries中,使用其中的动态代理。
运行结果:
Hello: 分享Java快乐
你好: 分享Java快乐
11. 自动绑定和依赖检查
这篇文章来谈谈《Spring Framework 开发参考手册》的3.3.5小节中的“自动装配协作对象”和3.3.6 小节中的“依赖检查”。
仔细看看文档,相关配置见前面文章。
先建立一个包:javamxj.spring.basic.autowiring ,然后把以下4个文件放在这个包下。
· HelloBean,一个简单的Bean,含有一个属性hello。
HelloBean.java |
package javamxj.spring.basic.autowiring;
public class HelloBean { private String hello;
public String getHello() { return hello; }
public void setHello(String hello) { this.hello = hello; }
} |
· HelloDate类先定义了三个构造函数,然后设置了三个属性:hello、date、date2。
HelloDate.java |
package javamxj.spring.basic.autowiring;
import java.util.Date; import java.util.GregorianCalendar;
public class HelloDate {
public HelloDate() { System.out.println("defalt Constructor called"); }
public HelloDate(HelloBean hello) { System.out.println("HelloDate(HelloBean) called"); }
public HelloDate(HelloBean hello, Date date) { System.out.println("HelloDate(HelloBean,Date) called"); }
public void setHello(HelloBean hello) { System.out.println("Property hello set"); }
public void setDate(Date date) { System.out.println("Property date set"); }
public void setDate2(GregorianCalendar date) { System.out.println("Property date2 set"); }
} |
· beans.xml中定义了七个bean,
xml version="1.0" encoding="GBK"?>
DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="date" name="myDate" class="java.util.Date"/>
<bean id="helloBean" class="javamxj.spring.basic.autowiring.HelloBean"
dependency-check="simple">
<property name="hello" value="javamxj"/>
< SPAN>bean>
<bean id="HelloByName" class="javamxj.spring.basic.autowiring.HelloDate"
autowire="byName"/>
<bean id="HelloByType" class="javamxj.spring.basic.autowiring.HelloDate"
autowire="byType"/>
<bean id="HelloConstructor" class="javamxj.spring.basic.autowiring.HelloDate"
autowire="constructor"/>
<bean id="HelloAutodetect" class="javamxj.spring.basic.autowiring.HelloDate"
autowire="autodetect"/>
<bean id="helloCheck" class="javamxj.spring.basic.autowiring.HelloDate" autowire="byType"
dependency-check="objects">
<property name="date2" >
<bean class="java.util.GregorianCalendar"/>
< SPAN>property>
< SPAN>bean>
< SPAN>beans>
Main.java |
package javamxj.spring.basic.autowiring;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource;
public class Main { public static void main(String[] args) { BeanFactory bf = new XmlBeanFactory(new ClassPathResource( "javamxj/spring/basic/autowiring/beans.xml"));
System.out.println("使用 byName:"); HelloDate hb = (HelloDate) bf.getBean("HelloByName");
System.out.println("\n使用 byType:"); hb = (HelloDate) bf.getBean("HelloByType");
System.out.println("\n使用 constructor:"); hb = (HelloDate) bf.getBean("HelloConstructor");
System.out.println("\n使用 autodetect:"); hb = (HelloDate) bf.getBean("HelloAutodetect");
System.out.println("\n使用 dependency-check:"); hb = (HelloDate) bf.getBean("helloCheck"); } } |
运行结果:
使用 byName:
defalt Constructor called
Property date set
使用 byType:
defalt Constructor called
Property date set
Property hello set
使用 constructor:
HelloDate(HelloBean,Date) called
使用 autodetect:
defalt Constructor called
Property date set
Property hello set
使用 dependency-check:
defalt Constructor called
Property date2 set
Property date set
Property hello set
参考运行结果,详细说明一下beans.xml的配置:
· HelloByName指定了autowire="byName",则Spring会根据bean的名称与属性名称是否符合来进行自动绑定。如这里HelloDate含有属性:hello、date、date2,在beans.xml中包含了date、helloBean两个bean,所以只有date符合要求。(bean的名称包括Id名称和name名称)
· HelloByType指定了autowire="byType",这里HelloDate含有属性:hello、date、date2,在beans.xml中包含了Date类和HelloBean类,分别匹配date和hello属性。
· HelloConstructor指定了autowire="constructor",它会优先调用含有较多参数的构造函数。
· HelloAutodetect指定了autowire="autodetect",如果找到了一个缺省的构造函数,则会应用byType。
· helloBean中指定了dependency-check="simple",则会对基本类型和集合进行依赖检查。这里如果不对属性hello进行赋值,就会抛出一个异常。
· helloCheck中指定了dependency-check="objects",同时也指定了autowire="byType",虽然会自动绑定属性date和hello,但由于属性date2没有被自动绑定到,所以需要特别设置。
posted on 2005-11-04 00:31
joes 阅读(625)
评论(1) 编辑 收藏 所属分类:
Spring