前言
在诞生之初,创建Spring的主要目的是用赖替代更加重量级的企业级java技术,尤其是EJB。相对于EJB来说,Spring提供了更加轻量级和简单的编程模型。他增强了简单老式java对象POJO的功能,使其具备了之前只有EJB和其他企业级Java规范才具有的功能。
简化java开发
为了降低java开发的复杂性,Spring采取了以下4中关键策略:
- 基于POJO的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程;
- 通过切面和末班减少样板式代码
激发POJO的潜能
我们能发现在java编程中,很多框架通过强迫应用继承他们的类或实现它们的接口从而导致应用与框架绑死,这种侵入式的编程在EJB2时代以及早期的Struts,WebWork中都能看到。
而在Spring构建的应用,不会强迫你继承或实现Spring规范的类或接口,甚至一个类或许使用了Spring注解,但他仍然是一个POJO。Spring竭力避免因自身的API而弄乱你的应用代码。
也就是说一个简单的普通类POJO,在Spring应用和非Spring应用都可以发挥同样的作用。
Spring赋予POJO这种能力的方式就是通过DI来装配他们。
依赖注入
依赖注入现在已经演变成一箱复杂的编程技巧和设计模式的理念,但其实它并没有那么复杂。
DI功能的实现。
在人任何有意义的应用中都存在两个或者更多的类,这些类相互协作来完成特定的业务逻辑。按照传统的做法,每个对象负责,管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高耦合和难以测试的代码。
因为耦合具有两面性,一方面,紧密耦合的代码难以测试复用和理解,并且表现出“打地鼠“的bug特性,(修复一个ebug,另一个又冒出来)另一方面,一定程度的耦合有事必须的–完全没有耦合的代码什么也做不了。
DI就是来应对耦合产生的对象管理。通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。对象无需自行创建或管理他们的依赖关系。如下图所示,依赖关系将被自动注入到需要他们的对象中去。
下面来看一段代码:
![在这里插入图片描述
上面是依赖注入方式的一种----构造器注入,可以将探险任务作为构造器参数传入,这样任何实现Quest接口的不同探险任务都能传入。
这里的BraveKnight没有与任何特定的Quest实现发生耦合。这就是DI带来的松耦合。如果一个对象通过接口而不是具体实现或者初始化过程来表示依赖关系,那么这种依赖就能在对象毫不知情的情况下用不同的具体实现来进行替换。(详细内容可看Spring实战1.1.2)
应用切面
面向切面AOP 的编程允许把遍布应用各处的功能分离出来形成可重用的组件。
有些系统服务(如日志事务管理和安全等)经常会融入到具有核心业务逻辑的组件中,会跨越系统的多个组件,因此被称为横切关注点。
如果将这些关注点分散到多个组件中去,代码将会带来双重的复杂性。
如下图,左边的业务对象和系统服务结合的过于紧密,每个对象不但要知道他需要记录日志和进行安全控制以及参与事务,还要亲自执行这些服务。
AOP能够使这些服务模块化,并以声明的方式将他们应用到他们需要影响的组件中去。使这些组件具有更高的内聚性并更加关注自身的业务,完全不需要了解涉及系统服务所带来的复杂性。总之AOP能够保持POJO的简单性。
如下图,我们可以把切面想象成覆盖在很多组件上的一个外壳。应用则是由那些实现各自业务功能的模块组成的。借助AOP,可以使用各种功能层去包裹核心业务层。这些层以声明的方式灵活的应用到系统中,核心应用不知道他们的存在。这是一个很强大的理念,可以将那些关注点与核心业务层相分离。
举个简单的例子,有个诗人对象,负责对骑士探险进行记载,他有两个方法,分别在骑士探险前后调用。于是在骑士类中需要注入如下:
但是这样不好,骑士类代码变得复杂了,因为骑士不应该负责管理诗人的对象,诗人应该做他自己的事情,而不是让骑士命令他做。于是使用AOP就可以将诗人抽象成一个切面,只需在Spring配置文件中中声明它就可以达到同样的效果。如下xml文件总配置诗人Minstrel为一个切面。
使用模板消除样板式代码
很多场景我们需要写大量重复的代码,如JDBC调用。Spring提供了样板式代码来解决这个问题(如JdbcTemplate)这里不再详细说明。