您的位置:首页 > 编程语言 > Java开发

spring简介-----阿冬专栏

2015-08-20 10:52 381 查看


Spring核心技术




来自:http://blog.csdn.net/laner0515/article/details/27973623

+]

这是第二次看关于Spring的资料,因为刚开始学习Spring的时候是边看视频边学习的,所以更注重的是实现代码,但是对宏观的掌握还是不够,这次主要从宏观的角度来分析一下Spring。

什么是Spring

Spring是分层的Java SE/EE应用一站式的轻量级开源框架,以IoC(Inverse of Control:反转控制)和AOP(AspectOriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,此外,Spring以海纳百川的胸怀整合了开源世界里众多注明的第三方框架的类库,逐渐成为使用最多的JavaEE企业应用开源框架


Spring的好处

首先,既然要学习和使用Spring,那么,我们就必须要知道使用Spring的好处,如果不能了解他的好处,就不能在适当的时候使用这个框架,当然也就失去了学习的意义。

方便结构,简化开发

通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编程所造成的过度程序耦合,有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

AOP编码的支持

通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

声明式事物的支持

在Spring中,我们可以从单调烦闷的十五管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。

方便程序的测试

可以用非容器以来的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事情。

方便集成各种优秀框架

Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架(如Struts,Hibernate,Hessian,Quartz等)的直接支持。

降低Java EE API的使用难度

Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低。

Java源码是经典学习范例

Spring的源码设计精妙、结构清晰、匠心独运,处处体现着大师对Java设计模式灵活运用以及对Java即使的高深造诣,Spring框架源码无疑是Java技术的最佳实践的范例。如果想在段时间内迅速提高自己的Java技术水平和应用开发水平,学习和研究Spring源码将会使你受到意想不到的效果。


Spring的体系结构

如果说Spring是一个人,那么AOP和IoC就是他的灵魂(AOP和IoC在之前博客已经讲到),而他的结构体系就是他的骨骼,所以,这里我们要详细的研究一下Spring的结构体系

一张图胜过千言万语



下面依次讲讲结构体系中每一个模块的内容

核心容器:

核心容器组成的核心,Beans,上下文和表达式语言模块,每一块的主要功能为:

spring 核心模块实现了 IOC 的功能,它将类和类之间的依赖从代码中脱离出来,用配置的方式进行依赖关系描述,由 loc 容器负责依赖类之间的创建、拼接、管理、获取等工作, BeanFactory 接口是Spring 框架的核心接口,它实现了容器许多核心的功能。

Context 模块构建于核心模块之上,扩展了 BeanFactory 的功能,添加了 i18n 国际化、 Bean生命周期控制、框架事件体系、资源加载透明化等多项功能。此外,该模块还提供了许多企业级服务的支持,如邮件服务、任务调度、JNDI 定位、 EJB 集成、远程访门等。

ApplicationContext是 Context 模块的核心接口。

表达式语言模块是统一表达式语言 (unified
EL) 的一个扩展,该表达式语言用于查询和管理运行期的对象,支持设置和获取对象属性,调用对象方法、操作数组、集合等。还提供了逻辑表达式运算、变量定义等功能·使用它就可以方便地通过表达式串和 Spring
IOC 容器进行交互。


数据访问/集成:

数据访问/集成层包括JDBC,ORM,OXM,JMS和事务处理模块,每一个模板的功能如下

JDBC模块提供了不再需要冗长的JDBC编码相关了JDBC的抽象层。

ORM模块提供的集成层。流行的对象关系映射API,包括JPA,JDO,Hibernate和iBatis。

OXM模块提供了一个支持对象/ XML映射实现对JAXB,Castor,使用XMLBeans,JiBX和XStream 的抽象层。

Java消息服务JMS模块包含的功能为生产和消费的信息。

事务模块支持编程和声明式事务管理实现特殊接口类,并为所有的POJO。

任何应用程序,其核心的问题是对数据的访问和操作。数据有很多表现形式,如数据表、XML、消息等,而每种数据形式又拥有不同的数据访问技术(如数据表的访问既可以直接通过JDBC,也可以通过Hirnate或iBatis)。
Spring站在DAO的抽象层面,建立了一套面向DAO层统一的异常体系,同时将各种访问数据的检查型异常转换为非检查型异常,为整合各种持久层框架提供基础。其次,Spnng通过模板化技术对各种数据访问技术进行了薄层的封装,将模式化的代码隐藏起来,使数据访问的程序得到大幅简化·这样,Spring就建立起了和数据形式及访问技术无关的统一的DAO层,借助AOP技术,Sp血g提供了声明式事务的功能。

Web:

在Web层包括网络,Web-Servlet,Web-Struts和网络的Portlet组件,其细节如下:

Web模块提供了基本的Web开发的集成特性,例如多方文件上传功能和使用的servlet监听器的IoC容器初始化和针对Web的应用程序上下文。

Web-Servlet模块包含Spring的模型-视图-控制器(MVC)实现Web应用程序。

Web-Struts模块包含支持类内的Spring应用程序集成了经典的StrutsWeb层。yiibai.com

Web-Portlet模块提供了MVC实现在portlet环境中使用和镜子Web的Servlet的模块的功能。yiibai.com



该模块建立在ApplicationContext模块块之上,提供了Web应用的各种工具类,如通过Listener或Servlet初始化Spring容器,将Sprmg容器注册到Web容器中。其次,该模块还提供了多项面向web的功能,如透明化文件上传、Velocity、FreeMarker、XSLT的支持。

此外,Spring可以整合Struts、WebWork、TapestryWeb等MVC框架。


其他:

还有像AOP,切面,规范,网络和测试模块,其详细情况如下其他一些重要的模块:

AOP模块提供了面向方面编程实现,允许您定义方法拦截器和切入点,以干净解耦,实现的功能,应该分开的代码。

Aspects模块提供与AspectJ的集成这又是一个功能强大且成熟的面向方面编程(AOP)框架。

Instrumentation模块提供了一定的应用服务器中使用类工具的支持和类加载器实现。

测试模块支持Spring组件使用JUnitTestNG框架的测试。

此外,Spring在远程访问以及WebService上提供了对很多著名框架的整合。由于Spring框架的扩展性,特别是随着spring框架影响性的扩大,越来越多框架主动地支持Spring框架,让spring框架应用涵盖面越来越宽广。

本博客主要借鉴了《Spring3.X企业开发应用实战》,一本非常系统的讲解Spring的书籍,推荐大家看一下



Spring中的IOC

在学习spring的时候,最常听到的词应该就是IOC和AOP了,下面,我从我的角度再次理解一下Spring里的IOC和AOP.

IOC简介

IoC(InversionofControl):IoC就是应用本身不依赖对象的创建和维护而是交给外部容器(这里为spring),这要就把应用和对象之间解耦,控制权交给了外部容器。即Don'tcallme,I'llcallyou!所以IoC也称DI(依赖注入)对象的创建和维护依赖于外部容器.

IOC详解

关于IOC的博客有很多,我们可以从这篇博客中了解一下:

深入浅出Spring(二)IoC详解

简单理解IOC

我们从文章中发现,其实ioc所做的一件事情就是把A和B的强耦合关系,变成A依赖于B的接口的关系,但具体A要实现B接口中哪一种B类型,由C来决定,以达到解耦,通俗来讲,我们在家到饭点的时候就会说“我要吃饭”,我这里代表的是A,饭代表的是B的接口,但是具体是要吃什么饭,那就由你的妈妈在决定,你妈妈给你在碗里放了米饭(B),你就要吃米饭,当然,今天你妈妈开心,也可以给你碗里放一个鸡腿,这个决定权在你的妈妈,也就是我们常说的把控制权交给第三方。一次来达到我(A)和米饭(B)的解耦。

DI与IOC 的关系

我们可能会经常听到另一个词:DI,这里,简单的做一下讲解:

因为IOC确实不够开门见山,因此业界曾进行了广泛的讨论,最终软件界的泰斗级人物MartinFowIer提出了DI(依注入:Dependency Injection)的概念用以代替loc,即让调用类对某一接口实现类的依赖关系由第三方(容器或协作类)注入,以移除调用类对某一接口实现类的依赖。“依賴注入”这个名词显然比“控制反转”直接明了、易于理解。

所以,我认为IOC和DI描述的是一件事情,只是从不同的角度来描述:

IOC控制反转:说的是创建对象实例的控制权从代码控制剥离到IOC容器控制,实际上就是我们现在说的第三方,侧重于原理。

DI依赖注入:说的是创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

说到DI,可能就会有出现这样一个问题,既然DI侧重实现,那么他是怎么实现的呢?也就是怎么注入的呢?下面我们

几种注入方式:

简单说一下几种注入方式:

第一种:构造函数注入(这里我们直接沿用上面的例子):

[html] view
plaincopy





publicclass Team {

privateLeader leader;

publicTeam(Leader leader){

this.leader=leader;

}

public void firstMetting(){

leader.introduce();

}

}

在Boss出的代码为:

public class Boss {

public void direct(){

Leader leader = new Li();

Team team = new Team(leader);

team.firstMetting();

}

第二种:属性注入:

有时,我们会发现,虽然小李在这个team里要发言,,但并非每次都要发言,在这种情况下通过构造函数注入并不妥当,这时可以考虑使用属性注入。属性注入可以有选择地通过setter方法完成调用类所需依赖的注入,更加灵活方便;

[html] view
plaincopy





public class Team {

privateLeader leader;

publicvoid SetLeader (Leader leader){

this.leader=leader;

}

public void firstMetting(){

leader.introduce();

}

}

在Boss出的代码为:

public class Boss {

public void direct(){

Leader leader = new Li();

Team team = new Team();

Team.setLeader(leader);

team.firstMetting();

}

和通过构造函数注入不同,在实例化Team时,并未指定任何发言人,而是在实例化Team后,在需要小李出场时,才调用其setLeader方法注入扮演者。按照类似的方式,这样,我们就可以在不同的场合,注入相应的发言人了。


第三种:接口注入:

[html] view
plaincopy





定义接口:

Public interface teamInject{

voidinjectLeader(Leader leader);

}

public class Team implements teamInject {

privateLeader leader;

publicvoid injectLeader (Leader leader){

this.leader=leader;

}

public void firstMetting(){

leader.introduce();

}

}

在Boss出的代码为:

public class Boss {

public void direct(){

Leader leader = new Li();

Team team = new Team();

Team.setLeader(leader);

team.firstMetting();

}

由于通过接口注入需要额外声明一个接口,增加了类的数目,而且它的效果和属性注

入并无本质区别,因此我们不提倡采用这种方式。

Spring中实现IOC

当然,在这个例子中,我们是通过手动维护第三方类的,那么,Spring容器是怎么实现的呢?

spring容器实现的方法网上也有很多,在这里,我就直接站在巨人的肩膀上了:

手动模拟IOC



其实,在Spring容器中,容器只是把第三方这个类对外封装成一个xml节点,在容器中进行查询注入,注意,这里用到两个非常重要的技术,一个是查找XML,另一个是根据方法名利用反射机制调用类。我感觉如果以后想写出好的程序,这两个技术是必不可少的。



IOC就讲到这里,下面讲一下我对AOP的理解:Spring中的AOP


Spring中的AOP

在上一篇博客中,我们讲了Spring的IOC,下面,我们继续讲解Spring的另一个核心AOP

AOP:

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP也是Action Oriented Programming 的缩写,意为:面向切面编程,是函数式编程的一种衍生范型。AOP在其他领域也有其他含义。

AOP的详解:

还是老规矩,站在巨人的肩膀上,看看其他人对AOP的理解:

手动模拟AOP

深入浅出Spring(三)AOP详解

动态代理——JDK和CGlib

为什么需要CGlib

以上两个例子都是应用JDK动态代理实现的AOP,但是,我们知道Spring给我们提供了两种实现代理的方式,一种是JDK的动态代理,还有一种是CGlib的动态代理,那么,为什么要提供CGlib代理呢?

使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点我们可从Proxy的接口newProxyInstance(CIassLoader loader,Class[] interfaces,InvocationHandIer h)的方法签名中就看得很清楚:第二个入参interfaces就是需要代理实例实现的接口列表。虽然而向接口编程的思想被很多大师级人物(包括RodJohnson)推崇,但在实际开发中,许多开发者也对此深感困惑:难道对一个简单业务表的操作也需要老老实实地创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和service实现类)吗?难道不能直接通过实现类构建程序吗?对于这个问题,我们很难给出一个孰好孰劣的准确判断,但我们确实发现有很多不使用接口的项目也取得了非常好的效果(包括大家所熟悉的SpringSide开源项目)。

对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然己经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。

CGLib实现动态代理

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。

因为和JDK动态代理原理一样,所以这里简单的写一下代理类的实现:

[html] view
plaincopy

packagecom.proxy.spring;

importjava.lang.reflect.Method;

importnet.sf.cglib.proxy.Enhancer;

importnet.sf.cglib.proxy.MethodInterceptor;

importnet.sf.cglib.proxy.MethodProxy;



publicclass CglibProxy implements MethodInterceptor {



private Enhancer enhancer = new Enhancer();



public Object getProxy(Class clazz){

enhancer.setSuperclass(clazz);

enhancer.setCallback(this);

return enhancer.create();

}



@Override

public Object intercept(Object obj, Methodmethod, Object[] args,

MethodProxy proxy) throws Throwable{

System.out.println(obj.getClass().getName()+"."+method.getName());

Objectresulet=proxy.invokeSuper(obj,args);

System.out.println("========end===================");

return resulet;

}

}

JDK和CGlib的差异:

JDK和CGlib除了在是否使用接口上的差异以外,在性能上也有一定的差异,理解这些差异,可以让我们更好的使用它们:

JDK动态代理所创建的代理对象,在JDK1.3下,性能强差人意,虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。但CGLib在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术,值得一提的是,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行代理。

Spring中的AOP

JDK和CGlib的一些缺陷

但是,以上我们说来说去,一直在说动态代理,虽然动态代理实现了AOP,但是,我们想一下我们实际的应用,就会发现有很多问题,当然,Spring AOP就是基础这些问题创建的:

1)目标类的所有方法都添加了性能监视横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑;

2)我们通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结東前织入代码;

3)我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的程序代码,无法做到通用。

Spring的解决方案

以上三个问题,在AOP中占用重要的地位,因为SpringAOP的主要工作就是围绕以上三点展开;SpringAOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。此外,Spring通过Advisor(切面)将Pointcut和Advice两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。

Spring中的AOP与IOC

在Spring容器里,我们可以发现,Spring容器包含各种增强类,比如前置增强,后置增强,环绕增强等,还有各种切点,切面,以解决上述动态代理所存在的一些问题,其实如何解决这些问题我们暂且不研究(研究起来可能就不是一篇博客可以写得完的了),总之,Spring已经把这些类都已经写好了,现在要使用这些东西,比如我们需要在一个add方法前面插入验证,那么我们应该怎么做呢?如果我们没有接触过Spring,一定会这样想,那就在和之前使用JDK或者CGlib动态代理一样直接调用不就好了吗:

[html] view
plaincopy

MyProxy hander = new MyProxy();

Animal dog = (Animal)hander.createProxyInstance(new Dog());

dog.run();

dog.jump();

这里我们很容易发现,代理已经和被代理的类耦合在一起了,这里我们就发现,我们伟大的IOC就需要出现来了,我们只需要把他们交给第三方来实现解耦合就可以了。

IOC和AOP如何是Spring变得强大

其实,最后这段话是我之前一直都没有想过的,因为之前一直在强调Spring的核心是IOC和AOP,只是在想IOC是什么?AOP是什么?从来没有把他们关联起来想,其实,从这里我们就可以看出,Spring的AOP其实是构建于IOC之上,和IoC浑然天成统一于Spring的容器之中,也就是说,如果没有Spring IOC,AOP是无法发挥他的强大的作用的,当然,如果没有Spring AOP,IOC还是有很多问题无法解决,同时,我们在想一下Spring的其他技术,比如事务,我们应该对事务比较清楚,Spring的事务就是被AOP到Spring中的,当然,还有比如对比如JDBC、Hibernate等的集成其实都是在Spring
IOC的基础上开花结果的。其实如果这样想下去,Spring的学习,就变成使用IOC或者AOP对已经存在的类的整合,随便什么类,反正拿过来控制依赖注入一下,或者是当切进去就可以为我们所用了,如果从这个角度看Spring,是不是就发现Spring变得简单而强大了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: