Spring 2.0读书笔记(一)
时间:2010-09-27 来源:棍子上的萝卜
无意间在图书馆的旧楼发现了Spring2.0技术手册(一般是流通量较低的书会放在旧馆),记得之前网上对其评价还算不错,随便翻了下只能说很顺眼,相比国内的一些浮躁的作者(大部分是一些错误百出的培训机构拉的后腿),台湾人确实在写书方面略胜一筹,可惜识货的不多,李刚之流的人的书籍堆满了新馆的书架,谁叫他的书流通量大呢。准备整理些东西以便以后总结之用,虽然Spring已经出了3.0,但是对于我这种从未接触过框架技术的java准菜鸟来讲什么版本都不算老....囧,就此拙劣的记录一下自己或对或错的读书理解,如果有幸有朋友看到我的笔记,权当是与和我一样第一次接触Spring的同学们共勉,学习之路应该是有相通点的。
第一天:皮毛:
Spring从基本功用来看,只是一个容器(想起tomcat这种Servlet容器,管理servlet以及其生命周期,对象之间的关系等等...仔细想想Spring管理的职责似乎也异曲同工),与其他框架类似,它通过现成的框架包精简了我们的代码量,更重要的是它实现了一个IoC容器(频繁出镜的词汇)。
何为IoC?
IoC(Inversion of Control)即控制反转,再多的措辞描述也只是一头雾水,用一个简单的例子来描述这个简单又重要的概念:
package luobo.test_one;
public class Father { //后面的Son类与其没有任何继承上的关系...仅仅只是叫Son回家吃饭
private Son son=new Son("JiaJunpeng"); //请允许我使用如此拙劣直接的对象注入
private String name; //后面将会用到区别两种方式的注入
public Father(String name){
this.name=name;
}
public void callSon(){
System.out.println(son+"!\t你妈妈喊你回家吃饭!!");
}
public String toString(){
return name;
}
}
Father类的callSon()将调用一个Son实例的toString()方法(覆盖自基类Object,我定义了Son类的toString()方法将返回Son的名字),形成了对Son类对象的依赖,这种依赖是直接主动的以及不可转变(除非你修改Father类,如果应用程序非常大,这将与在大型的依赖关系网中捅一个洞并无二样)的.对于应用程序的维护是极为不便的,试想如果又生了一个儿子呢?并且唐突的声明对某一个具体类的依赖也是错误的,试想如果贾君鹏其实是个女孩....或者贾君鹏只是别人的孩子,自然而然的你肯定会想到定义一个IChild接口,让需要被叫唤的孩子(无论你是侄子侄女抑或是孙女)实现这个接口:
package luobo.test_one;
public interface IChild {
//.........balabala定义............
}
而相应Father类修改如下:
Father.java
package luobo.test_one;
public class Father {
private IChild child;
private String name; // 后面将会用到
private String word;
public Father() {
}
public Father(String name) { // 区别于IChild类型属性.使用构造方式注入 Type2 IoC
this.name = name;
}
public void callSon() {
System.out.println(this.toString() + "说: " + child + "!\t" + word);
}
public String toString() {
return name;
}
public void setChild(IChild child) { // 使用setter getter方法注入 Type3 IoC
this.child = child;
}
public IChild getChild() {
return child;
}
public void setWord(String word) {
this.word = word;
}
public String getWord() {
return word;
}
}
但这样并没有完全形成IoC,仅仅只是解决了整个系统的重用性问题,简单的实现了依赖关系的转移(当然依赖于抽象是Spring的Ioc的核心理念之一),使得高层抽象模块与底层实现一定程度的松耦,Father类依赖于IChild以及String对象,并分别通过Setter以及构造函数所保留的接口(此接口非传统意义上的接口)来完成对象资源的注入。
进而Spring可以通过设置来转变应用程序对其所需资源的的主动依赖,IoC容器帮助应用程序(如Father类)获取资源并注入它,整个过程Father类都是被动接受,修改相应的xml配置文件(此文件放在Eclipse工程的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" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="father" class="luobo.test_one.Father">
<constructor-arg>
<value>ZhenJunpeng</value>
</constructor-arg>
<property name="word" value="你妈妈喊你回家吃饭"></property>
<property name="child">
<ref bean="son" />
</property>
</bean>
<bean id="son" class="luobo.test_one.Son">
<property name="name" value="JiaJunpeng"></property>
</bean>
</beans>
注:在上面我们设置了Son类的一个bean,如果Son类只会被调用一次或者你不怕麻烦多次完成输入Son的全名也可以如下改变
<ref bean="son"/> =========><bean class="luobo.test_one.Son">
所有的bean设置都已经完成了,万事俱备只欠东风,这时我们写一个callBack类来完成这次叫唤活动。
callBack.javapackage luobo.test_one;
public class callBack {
public static void main(String[] args) {
// TODO Auto-generated method stub
Father father = new Father();
father.callSon();
}
}
呃~然获得下面的输出结果是可想而知的:
null说: null! null
我们忘记创建Spring框架内置的ApplicationContext对象来读取xml文件(虽然BeanFactory对象也能完成基本的容器管理功能,但是很显然ApplicationContext由于它支持的更多,两者的差距一言难尽,总之开始就使用ApplicationContex应该是个好习惯)来完成对象的依赖注入。
callBack.java修改如下
package luobo.test_one;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class callBack {
public static void main(String[] args) {
// TODO Auto-generated method stub
//通过ApplicationContext读取ClassPath路径下的xml文件,也可以以String[]的方式读取多个
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Father father = (Father)context.getBean("father"); //获取name为father的bean对象
father.callSon();
}
}
输出:
ZhenJunpeng说: JiaJunpeng! 你妈妈喊你回家吃饭。
上面就是一个简单的IoC容器使用的例子,你之后可以方便的通过设置xml来实现对象间的依赖关系,而从各个类表面来看是完全看不出有任何的耦合性的,应用程序仅仅只是保留资源的进入方式(虚位以待),最终是由容器读取xml来实现资源的注入,Father完全处于被动状态(可以将容器想象为Mother),他并不清楚自己要去叫谁干什么。在容器的角度用一句概括:don’t ask me! i'll call you ...。
第一天备忘:
1)bean可通过<alias name="xxxx">设置别名 可通过别名获得此bean
2)通过<bean id="xxx" class="xxxxxxx.xxxx.xx" factory-bean="方法名">来指定静态工场方法来取得对象实例。
3)IoC的两种形式 Type 2(通过setter getter)与Type 3(通过构造函数注入) 各有特点。前者更形象,后者更直接
4)每一个Bean被取后默认只保持一个实例---singleton,即两次context.getBean("father")产生的对象只有一个。通过<bean id="xxx" class="xxxxxxx.xxxx.xx" scope=“[prototype]|[request]|[session]|[globalSession]">分别表示每次都产生一个新实例|请求阶段|会话阶段|应用程序阶段。
5)bean的定义可以继承 (注意:与类的继承有相似但是本质上完全不同)对于多个类似属性设值一致的情形,可以考虑。
如<bean id="inheritedBean" abstract="true">它将不能被实例化 当然也可以设为普通的类
.......................
</bean>
<bean id="someBean" class parent="inheritedBean">
.............................所有与父bean定义相同的属性值都一致 除非你重新设值覆盖。
6)在使用构造函数注入时候可以<construtor-arg index="0">的方式来指定第一个参数,以此类推
7)当没设置依赖关系但需要另一个bean在本类之前实例化的话可以引入depend-on="xxxxxx.xxxxx"属性