简单来说,Spring是一个轻量级得到控制反转和面向切面的容器框架
至于IOC和AOP则是Spring的灵魂,这两点搞清楚,Spring就很容易理解了,下面我就来介绍这两个特性
AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。控制反转是依赖倒置原则的一种代码设计思想。具体采用的方法就是所谓的依赖注入(DI)
在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
<bean class="com.ujiuye.demo.pojo.Human" id="human4">
<constructor-arg name="name" value="aa"/>
<constructor-arg name="age" value="21"/>
bean>
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
<bean class="com.ujiuye.demo.pojo.Human" id="human5">
<property name="name" value="dd"/>
<property name="age" value="12"/>
bean>
private String[] arr;
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
<bean class="com.ujiuye.demo.pojo.Human" id="human6">
<property name="arr">
<array>
<value>avalue>
<value>bvalue>
<value>cvalue>
<value>dvalue>
array>
property>
bean>
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
<bean class="com.ujiuye.demo.pojo.Human" id="human7">
<property name="list">
<list>
<value>aavalue>
<value>bbvalue>
<value>ccvalue>
<value>ddvalue>
list>
property>
bean>
private Set<String> set;
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
<bean class="com.ujiuye.demo.pojo.Human" id="human8">
<property name="set">
<set>
<value>aaavalue>
<value>bbbvalue>
<value>cccvalue>
<value>dddvalue>
set>
property>
bean>
private Map<String, String> map;
<!--map注入-->
<bean class="com.ujiuye.demo.pojo.Human" id="human9">
<property name="map">
<map>
<entry key="x" value="X"></entry>
<entry key="y" value="Y"></entry>
<entry key="z" value="Z"></entry>
</map>
</property>
</bean>
private Properties properties;
<!--Properties注入-->
<bean class="com.ujiuye.demo.pojo.Human" id="human10">
<property name="properties">
<props>
<prop key="h">H</prop>
<prop key="j">J</prop>
<prop key="k">K</prop>
</props>
</property>
</bean>
private Dog dog;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
<bean class="com.ujiuye.demo.pojo.Dog" id="dog">
<property name="age" value="2"/>
<property name="name" value="d"/>
bean>
<bean class="com.ujiuye.demo.pojo.Human" id="human11">
<property name="dog" ref="dog"/>
bean>
beans>
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。