对于Spring的作用和体系结构这些,虽然在文档和视屏上都有所了解,不过我还是认为没有实践就出不了真知,所以还是先通过一些小的Demo来体味其魅力,然后再总结自己的心得。废话不多说,先看第一个Spring实例的文件结构图:
这里应该注意到我用的当然是Spring2.5
本例中,有SequenceGenerator.java,SuffixGenerator.java,DateSuffixGenerator.java三个关键文件,SequenceGenerator.java用来生成一个序列,接口SuffixGenerator.java用来获取序列的后缀生成器,DateSuffixGenerator.java用生成通过日期获取的后缀生成器。OK,详细请见三个类文件:
SuffixGenerator.java:
package beans;
public interface SuffixGenerator {
//获取后缀
public String getSuffix();
}
DateSuffixGenerator.java:
package beans;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateSuffixGenerator implements SuffixGenerator{
//pattern表示一个日期格式,比如yyMMdd
private String pattern;
public void setPattern(String pattern){
this.pattern = pattern;
}
@Override
public String getSuffix() {
// TODO Auto-generated method stub
return new SimpleDateFormat(pattern).format(new Date());
}
}
SequenceGenerator.java:
package beans;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
class SequenceGenerator {
private String prefix; //前缀
private SuffixGenerator suffixGen; //后缀生成器
private int initial; //初始值
private int counter; //计数器
private List<String> list = new ArrayList<String>();
private Set<String> set = new HashSet<String>();
private Map<String, Integer> map = new HashMap<String, Integer>();
/**
* 使用Spring的IoC需要每个属性有一个setter
* 还需要有一个无参的构造方法
*/
public SequenceGenerator() {
super();
}
public SequenceGenerator(String prefix, int initial) {
super();
this.prefix = prefix;
this.initial = initial;
}
public SequenceGenerator(String prefix, SuffixGenerator suffixGen, int initial) {
super();
this.prefix = prefix;
this.suffixGen = suffixGen;
this.initial = initial;
}
public void setList(List<String> list) {
this.list = list;
}
public void setSet(Set<String> set) {
this.set = set;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void setSuffixGen(SuffixGenerator suffixGen) {
this.suffixGen = suffixGen;
}
public void setInitial(int initial) {
this.initial = initial;
}
public void setCounter(int counter) {
this.counter = counter;
}
public synchronized String getId() {
StringBuffer sb = new StringBuffer();
sb.append(prefix);
sb.append(initial + counter++);
sb.append(suffixGen.getSuffix());
for (String s : list) {
System.out.println("list--->" + s);
}
for (String ss : set) {
System.out.println("set--->" + ss);
}
for (Entry<String, Integer> e : map.entrySet()) {
System.out.println(e.getKey() + "/" + e.getValue());
}
return sb.toString();
}
}
我们知道,在Struts2和Hibernate中,配置文件都起着至关重要的作用,Spring也不例外,对JavaBean的反转控制主要就是通过配置文件来实现的,初学者可以理解为向Spring注册JavaBean。通常会用beans.xml或者application.xml来命名该文件,不过这并不是必须的,因为其名称会在加载Context的时候由程序员自己给出。
beans.xml:
<?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-2.5.xsd">
<bean id="dateSuffixGenerator" class="beans.DateSuffixGenerator">
<property name="pattern" value="yyyyMMdd" />
</bean>
<bean id="sequenceGenerator" class="beans.SequenceGenerator">
<!-- IoC反转控制用主要用的是DI(依赖注入)设计模式实现的 -->
<!-- 构造注入 -->
<constructor-arg index="0" value="prefix" />
<constructor-arg index="1">
<ref bean="dateSuffixGenerator" />
</constructor-arg>
<constructor-arg index="2" value="10000" />
<!-- 设置注入 -->
<!-- List的注入方式 -->
<property name="list">
<list>
<value>aaaa</value>
<value>bbbb</value>
<value>cccc</value>
</list>
</property>
<!-- Set的注入方式 -->
<property name="set">
<set>
<value>AAAA</value>
<value>BBBB</value>
<value>CCCC</value>
</set>
</property>
<!-- Map的注入方式 -->
<property name="map">
<map>
<entry key="AaAaAa"><value>123</value></entry>
<entry key="BbBbBb"><value>435</value></entry>
</map>
</property>
</bean>
</beans>
Spring的IoC是通过DI设计模式来实现的,在beans.xml中关键就是对JavaBean属性的值就行依赖注入,有两种注入方式:构造注入和设置注入。通过上面的文件可以看出,这两种注入方式可以混用。需要注意的是,设置注入必须给相应的属性提供setter,另一点,该Bean需要有一个无参的构造方法。
OK,下面看看测试。
Test.java:
package beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// SequenceGenerator s = new SequenceGenerator("prefix","suffix",10000);
// 初始化spring的ApplicationContext(初始化容器)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 通过context获取在beans.xml中配置的bean
SequenceGenerator s = (SequenceGenerator) context.getBean("sequenceGenerator");
for (int i = 0; i < 5; i++) {
String id = s.getId();
System.out.println("id" + i + "=" + id);
}
}
}
我们当然可以通过注释掉了的方式获取生成器(如果在SequenceGenerator类中没有后来添加的几个List,Set,Map属性),不过这里讲的就是Spring对JavaBean的管理。
要让Spring来管理Beans,需要先让Spring读取到对Bean的注册,这里是beans.xml,获取应用的上下文ApplicationContex的t对象context。每个Bean的实例都是通过这个context对象的getBean(String beanId)方法获取的。
此外,需要知道以下:
1、通过这种方式获取的实例其实是单例的,如果不想用单例模式,可以在<bean>中添加属性scope,给出作用域值prototype,singleton等(默认为singleton)。
2、并非JavaBean的每个属性都要通过constructor或者setter设置值,这要看<bean>的另一个属性dependency-check,依赖检查的值为true或者false。
OK,Spring的第一个实例就是这样了,当然还有基于Annotation方式的,这要在下一篇blog中说了。过多的理论先不说,尽管我已经看了不少,还是放在适当的时机再说吧,免得误导了别人也误导了自己。