Spring实战笔记1
由于要转向javaweb方向,所以最近以及以后很长一段时间都要钻研javaweb相关的知识,人说转行穷三年,说起来我这跟转行也差不多,因为之前从来没有涉及到javaweb的工作,经验上固然不足,所以要在其他方面上抓紧啊,所以我选择一个一箭双雕的策略,哈哈,说起来也没有那么高明,只是要计划稳扎稳打,以坚实的基础知识,来弥补经验上的不足,之前已经粗浅的学习了jsp以及struts,虽然没有写专门的博客来记录,但jsp和struts的也还差着很多知识的,鉴于struts1的应用目前可能很少了,所以没有太深的研究struts,基础差不多是有的了,所以要学习一些新的东西才有竞争力。
java基本的ssh(struts+Spring+hibenate)框架是都需要了解的,但目前Spring的技术好像比较流行,应用的也比较多,所以本文章以及接下来的一些列文章将会伴随着我的学习过程来展示Spring的用法以及特点和技巧,如果有相同志向的朋友,可以来提点几句,大家相互学习。
我初识Spring是一本《Spring in Action》的中文版,所以本系列文章也是围绕着这本书的章节次序一次展示的。最首先是第一部分,该部分涵盖了Spring的一些核心的用法,可以说以后其他的模块,都是围绕着该核心展开的,当然其中也涉及了一些比较高明的编程思想,值得深究。废话少说,下面进入正题。
概论
第一部分的内容主要是介绍Spring基于依赖注入(DI)和面向切面编程(AOP)的思想,这是Spring的主要特性,所有功能都是围绕着这两个思想展开的,为的是简化大家的java开发,让我们把注意力能更多的放到业务逻辑当中。通过Spring的依赖注入以及面向切面编程,可以实现模块之间的松耦合,学过软件工程的人都应该知道,软件工程一直所最求的就是程序的高内聚和低耦合,其实我不是学软件工程的,这段是引用我老总的话,虽然我不是软件工程的专业,但是我也知道有高内聚低耦合这事儿,不管是企业级或者非企业级,java、c++或者其他任何语言,只要是模块化开发,那就必须要尽量保证高内聚低耦合,面向对象编程的23个基本的设计模式,说白了都是围绕这这个核心展开的,期中有一个动态代理模式让我很是忘不了,因为在动态代理模式中提到了面向切面编程的思想,当时看的时候还不是很明白,我知道有面部相对象,有面向过程,这个面向切面是个啥了,当时我也没有深究,但是动态代理那里提到一句Spring,说Spring很好的实现了面向切面编程,到现在开始学习Spring的时候才真正理解了面向切面编程,所以可以证明的是当时的动态代理的用法也是含糊不清啊。至于依赖注入我倒是第一次听见这个词儿,在学习了一段时间之后才觉得以前见过类似的东西,java有六个设计原则(本文章不是讨论java的设计模式,所以该部分内容不加深究),期中有一个是叫做依赖倒置,概念和依赖注入颇有相似,说的抽象一点,就是面向接口编程,类之间的依赖关系是通过接口而不是实现类(在依赖倒置的原则中,是这么说的,类之间的依赖是通过接口或者是抽象类,这里说道面向接口编程,自然就把抽象类去掉了)。当然这是最佳的方式,Spring提供了依赖注入,而没有说你注入的必须是接口,同样可以在在javaBean中使用实现类当作属性,这是留给开发者自己选择的(这提醒一句,还是用接口的好,如果你不信,往下看,慢慢你就信了),关于依赖注入以及面向切面编程具体是什么,一下会有详细记录,当然期中不乏有书中的原话,但大多也是我个人的理解。
书中总结了一些比较精辟的言语,所以不得不拿来用一下,一遍展开学习,期中有一段是说Spirng的四种关键策略(对于一些基本术语如果部清楚是什么概念的话大家就找度娘吧或者google,这里就展开介绍了)。
* 基于POJO的轻量级和最小侵入性编程
* 通过依赖注入和面向接口实现松耦合
* 基于切面和惯例进行声明式编程
* 通过切面和模板减少样板式代码
最初看这几句话的时候我也不怎明白,但后来有些意会了,但是要言传还是不得的,只能说这些思想贯穿了整个Spring,深入到了Spring的各个模块之中。
依赖注入
任何一个有实际意义的程序都由两个或者以上的类组成,类与类之间或多或少都会相互依赖,以助于这些类相互之间协作来完成特定的业务逻辑,通常每个对象负责管理与自己相互写作的对象(也就是他所依赖的对象)的引用,这将会倒置类与类之间高度的耦合,以及难以测试,比如我这里有一个衣服的类(Clothes)
class Clothes {}
他现在是一个空类什么都没有,衣服是要给人穿的,所以我们再制造一个人出来(ZhangSan)
class ZhangSan{
private String name = "ZhangSan"
public String getName(){
return name;
}
}
//更改之后的衣服类
class Clothes{
private Zhangsan zhangsan = null;
public Clothes(ZhangSan zhangsan){
this.zhangsan = zhangsan;
}
public void ShowName(){
System.out.println("穿我衣服的人是"+this.zhangsan.getName());
}
}
现在我们已经把zhangsan通过构造器注入注入到了Clothes类中,那么现在这件衣服zhangsan就穿上,当然如果这件衣服是贴身衣物的话,那自然是不能再给别人穿的,那么像我们如上这么处理就在何时不过类,除了zhangsan其他人也穿不上,当然最好zhangsan是一个单例类,这样世上就只有一个zhangsan了,不再纠结这个,我们再考虑另外一种情况,这是在衣服店里试衣服的场景,如果有这么一家店如果你试了这件衣服那么就必须买,别人再也穿不得,那你肯定要抓狂了,黑店,但是在天朝应该还没有这样的店或者是我没遇到过,所以按照正常的情况,一件衣服是个人都可以来试穿(大小不合适穿不上这些我们就暂且不考虑了),那么我们这个Clothes类就需要改一改了,如下
//创建一个新的接口Person
interface Person{
public String getName();
}
//修改后的ZhangSan
class ZhangSan implements Person{
private String name = "ZhangSan";
@Override
public String getName(){
return name;
}
}
//修改之后的Clothes类
class Clothes{
private Person person = null;
public Clothes(Person person){
this.person = person;
}
public void showName(){
System.out.println("穿着衣服的人是"+this.person.getName());
}
}
修改之后的效果就是只要实现了Person接口的人都可以穿衣服,这几段代码很简单,简直不能再简单了,但是其中却包含了依赖注入以及面向接口的编程思想,看Clothes类,他Person这个接口,只要实现了该接口的人都可以穿衣服,这样就不用为每一个人都写一个Clothes类了,这是代码的可重用性,而且面向接口编程还有利于单元测试,同时也实现了松耦合,两个实现类中没有直接的依赖,而依赖注入,在Clothes类中利用了 构造函数注入注入依赖,还有通过参数注入依赖,或者通过setter方法注入依赖,通过这个简单的例子,应该可以大概说明依赖注入以及面向接口编程的基本方法,后续还会说到比较高级的用法。
下面且来看看Spring是如何依赖注入的,还是以上的两个类(ZhangSan Clothes)。
创建组件之间协作的行为通常成为 装配 Spring有多重装配Bean的方式,最常用的就是采用xml配置,以下配置文件让Clothes接受一个Person
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="clothes" class="Clothes">
<constructor-arg ref="zhangsan"/>
</bean>
<bean id="zhangsan" class="ZhangSan"/>
</beans>
在这个配置文件中我们定义了Clothes类和ZhangSan类的关系,之后只需要装载xml配置文件并把应用启动起来就可以了
ApplicationContext context = new ClassPathXmlApplicationContext("clothes.xml");
Clothes clothes = (Clothes)context.getBean("clothes");
clothes.showName();
这里创建了一个Spring的应用上下文,该上下文加载了clothes.xml文件,随后在应用上下文中取了一个id为clothes的Bean之后简单调用showName()方法就可以知道是谁穿着衣服了。在这个例子中张三不知道自己穿着衣服,而衣服也不知道是谁在穿着自己(这听起来有点匪夷所思),只有clothes.xml文件知道,谁穿着什么衣服。这就是一个简单的Spring应用,之后的学习会对依赖注入有更深入的理解。
面向切面编程
依赖注入让相互协作的组件保持松散耦合,而AOP编程允许你把遍布应用各处的功能分离出来形成可重用组件。(引入书中原句,个人觉得说的很贴切)。
面向切面编程其实有点类似中介者模式,模块或者类之间的耦合协作交给一个中间件去处理,而各个模块之间只依赖中间件,但是面向切面编程却有不一样的地方,面向切面编程应该是很好的实现了开闭原则(对扩展开放,对修改关闭),在扩展的时候只需要重新开发一个模块,然后通过织入切面的方式将新模块加到原有的应用中去。
在软件开发中,分布与应用中多处的功能被成为横切关注点,将这些横切关注点与业务逻辑相分离正式面写切面编程(AOP)所要解决的。(引入书中原句)突然发现写着写着就出现越来越多书中的语句,真是不应该,我又不是想把书搬上来,只是说一下我自己的理解,等到涉及比较专业的内容时候,比如如何装配Bean,装配Bean的集中方式,以及应用声明来织入切面等。用通俗的点话来说面向切面编程,那就好像每个对象的表面都是一面镜子,而对象执行方法的环境中早已不满了各种传感器,就好像红外传感器一样,对象只要一有动作,返回回来的红外或者是什么其他光束信号就会改变,然后运行环境会做出相应的处理,说起来像是事件处理机制,但是面向切面编程比事件处理就高明多了,就拿观察着模式来说吧,需要给每个被观察者对象中都加上观察着的列表,在调用某个方法的时候同调用观察着的方法,而面向切面编程是通过代理实现的, 在应用调用对象的时候不是直接调用对象的实体,而是调用该对象的代理,所以可以在代理类中添加额外的操作这样不用修改对象实体的类也可以完成事件处理机制的功能,同时又实现了中介者模式的优点(类间解耦),切面所使用的场景类如日志,声明式事物,安全,缓存等。
我跟着上边的例子假设一个场景,比如张三不是一个人来买衣服,他是和李四一起来了,然后两个人千挑万选,选中了意见衣服,然后李四会给张三提出意见,也就是这件衣服好不好看,我们可以假设李四是一个阿谀奉承的人,不管好看不好看他多会说好看所以我们写一个李四的类,李四不是要买衣服的人,所以不用实现Person接口,类里只有一个方法就是告诉张三这件衣服穿在你身上真好看
class LiSi{
public void praise(){
System.out.println("你穿这件衣服真好看");
}
}
可以看的出来,李四也不知道自己说的是谁穿衣服好看,我们来修改一下clothes.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" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
">
<bean id="clothes" class="Clothes">
<constructor-arg ref="zhangsan"/>
</bean>
<bean id="zhangsan" class="ZhangSan"/>
<bean id="lisi" class="LiSi"/>
<aop:config>
<aop:aspect ref="lisi">
<aop:pointcut id="showName" expression="execution(* Clothes.showName(...))"/>
<aop:after pointcut-ref="showName" method="praise"/>
</aop:aspect>
</aop:config>
</beans>
以上这样配置就为张三织入了一个李四的切面,在衣服被张三穿上的时候,李四就会打印出"你穿这件衣服真好看"。
本文大概的描述了一下Spring的射击思想以及,用一个小例子来实现了依赖注入以及织入切面,接下来的一篇当中会详细介绍如把javaBean装配到Spring容器中去。