Spring的模块化是很强的各个功能模块都是独立的我们可以选择的使用这一章先从Spring的IoC开始所谓IoC就是一个用XML来定义生成对象的模式我们看看如果来使用的
数据模型
如下图所示有三个类Human(人类)是接口Chinese(中国人)是一个子类American(美国人)是另外一个子类
源代码如下
package chengangspring;
public interface Human {
void eat();
void walk();
}
package chengangspring;
public class Chinese implements Human {
/* (非 Javadoc)
* @see chengangspringHuman#eat()
*/
public void eat() {
Systemoutprintln(中国人对吃很有一套);
}
/* (非 Javadoc)
* @see chengangspringHuman#walk()
*/
public void walk() {
Systemoutprintln(中国人行如飞);
}
}
package chengangspring;
public class American implements Human {
/* (非 Javadoc)
* @see chengangspringHuman#eat()
*/
public void eat() {
Systemoutprintln(美国人主要以面包为主);
}
/* (非 Javadoc)
* @see chengangspringHuman#walk()
*/
public void walk() {
Systemoutprintln(美国人以车代步有四肢退化的趋势);
}
}
对以上对象采用工厂模式的用法如下
创建一个工厂类Factory如下这个工厂类里定义了两个字符串常量所标识不同的人种getHuman方法根据传入参数的字串来判断要生成什么样的人种
package chengangspring;
public class Factory {
public final static String CHINESE = Chinese;
public final static String AMERICAN = American;
public Human getHuman(String ethnic) {
if (ethnicequals(CHINESE))
return new Chinese();
else if (ethnicequals(AMERICAN))
return new American();
else
throw new IllegalArgumentException(参数(人种)错误);
}
}
下面是一个测试的程序使用工厂方法来得到了不同的人种对象并执行相应的方法
package chengangspring;
public class ClientTest {
public static void main(String[] args) {
Human human = null;
human = new Factory()getHuman(FactoryCHINESE);
humaneat();
humanwalk();
human = new Factory()getHuman(FactoryAMERICAN);
humaneat();
humanwalk();
}
}
控制台的打印结果如下
采用Spring的IoC的用法如下
在项目根目录下创建一个beanxml文件
<?xml version= encoding=UTF?>
<!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN beansdtd>
<beans>
<bean id=Chinese class=chengangspringChinese/>
<bean id=American class=chengangspringAmerican/>
</beans>
beanxml的位置如下图注意不要看花眼把它看成是lib目录下的了它是在myspring目录下的
修改ClientTest程序如下
package chengangspring;
import orgntextApplicationContext;
import orgntextsupportFileSystemXmlApplicationContext;
public class ClientTest {
public final static String CHINESE = Chinese;
public final static String AMERICAN = American;
public static void main(String[] args) {
// Human human = null;
// human = new Factory()getHuman(FactoryCHINESE);
// humaneat();
// humanwalk();
// human = new Factory()getHuman(FactoryAMERICAN);
// humaneat();
// humanwalk();
ApplicationContext ctx = new FileSystemXmlApplicationContext(beanxml);
Human human = null;
human = (Human) ctxgetBean(CHINESE);
humaneat();
humanwalk();
human = (Human) ctxgetBean(AMERICAN);
humaneat();
humanwalk();
}
}
从这个程序可以看到ctx就相当于原来的Factory工厂原来的Factory就可以删除掉了然后又把Factory里的两个常量移到了ClientTest类里整个程序结构基本一样
再回头看原来的beanxml文件的这一句
<bean id=Chinese class=chengangspringChinese/>
id就是ctxgetBean的参数值一个字符串class就是一个类(包名+类名)然后在ClientTest类里获得Chinese对象就是这么一句
human = (Human) ctxgetBean(CHINESE)
因为getBean方法返回的是Object类型所以前面要加一个类型转换
总结
()也许有人说IoC和工厂模式不是一样的作用吗用IoC好象还麻烦一点
举个例子如果用户需求发生变化要把Chinese类修改一下那么前一种工厂模式就要更改Factory类的方法并且重新编译布署而IoC只需要将class属性改变一下并且由于IoC利用了Java反射机制这些对象是动态生成的这时我们就可以热插拨Chinese对象(不必把原程序停止下来重新编译布署)
()也许有人说即然IoC这么好那么我把系统所有对象都用IoC方式来生成
注意IoC的灵活性是有代价的设置步骤麻烦生成对象的方式不直观反射比正常生成对象在效率上慢一点因此使用IoC要看有没有必要我认为比较通用的判断方式是用到工厂模式的地方都可以考虑用IoC模式
()在上面的IoC的方式里还有一些可以变化的地方比如beanxml不一定要放在项目录下也可以放在其他地方比如chengangspring包里不过在使用时也要变化一下如下所示
new FileSystemXmlApplicationContext(src/cn/com/chengang/spring/beanxml)
另外beanxml也可以改成其他名字这样我们在系统中就可以分门别类的设置不同的beanxml
()关于IoC的低侵入性
什么是低侵入性?如果你用过Struts或EJB就会发现要继承一些接口或类才能利用它们的框架开发这样系统就被绑定在StrutsEJB上了对系统的可移植性产生不利的影响如果代码中很少涉及某一个框架的代码那么这个框架就可以称做是一个低侵入性的框架
Spring的侵入性很低HumenjavaChinesejava等几个类都不必继承什么接口或类但在ClientTest里还是有一些Spring的影子FileSystemXmlApplicationContext类和ctxgetBean方式等
现在低侵入性似乎也成了判定一个框架的实现技术好坏的标准之一
()关于beanxml的用法
beanxml的用法还有很多其中内容是相当丰富的假设Chinese类里有一个humenName属性(姓名)那么原的beanxml修改如下此后生成Chinese对象时陈刚这个值将自动设置到Chinese类的humenName属性中而且由于singleton为true这时生成Chinese对象将采用单例模式系统仅存在一个Chinese对象实例
<?xml version= encoding=UTF?>
<!DOCTYPE beans PUBLIC //SPRING//DTD BEAN//EN
beansdtd>
<beans>
<bean id=Chinese class=chengangspringChinese singleton=true>
<property name=humenName>
<value>陈刚</value>
</property>
</bean>
<bean id=American class=chengangspringAmerican/>
</beans>
关于beanxml的其它用法不再详细介绍了大家自己拿Spring的文档一看就明白了