关闭

关闭

封号提示

内容

首页 SPRING源码解析.doc

SPRING源码解析.doc

SPRING源码解析.doc

上传者: hujianopp 2014-04-21 评分 3 0 37 5 170 暂无简介 简介 举报

简介:本文档为《SPRING源码解析doc》,可适用于IT/计算机领域,主题内容包含Spring技术内幕Spring技术内幕在应用开发中常常涉及服务器系统中各种不同进程之间的通信与计算交互远端调用(RMI)是实现这种计算场景的一种有符等。

Spring技术内幕Spring技术内幕在应用开发中常常涉及服务器系统中各种不同进程之间的通信与计算交互远端调用(RMI)是实现这种计算场景的一种有效方式。此外还存在着另一种情况在这种应用场景中与那些典型的基于HTML的BS应用不同客户端程序需要完成对服务器端应用的直接调用这也是需要远端调用大显身手的场合。Spring中提供了轻量级的远端调用模块从而为我们在上面提到的应用场景开发提供平台支持。根据Spring的既定策略它依然只是起到一个集成平台的作用而并不期望在实现方案上与已有的远端调用方案形成竞争。也就是说在Spring远端调用架构中具体的通信协议设计、通信实现以及在服务器和客户端对远端调用的处理封装Spring没有将其作为实现重点在这个技术点上并不需要重新发明轮子。对Spring来说它所要完成的工作是在已有远端调用技术实现的基础上通过IoC与AOP的封装让应用更方便地使用这些远端调用服务并能够更方便灵活地与现有应用系统实现集成。通过Spring封装以后应用使用远端过程调用非常方便既不需要改变原来系统的相关实现接口也不需要为远端调用功能增加新的封装负担。因此这种使用方式在某种程度上可以称为轻量级的远端调用方案。在实现远端调用的过程中往往需要涉及客户端和服务器端的相关设置这些设置通过Spring的IoC容器就可以很好的完成这是我们已经很熟悉的IoC容器的强项了。同时Spring为远端调用的实现提供了许多不同的方案玲琅满目任君选择。如RMI、HTTP调用器、第三方远端调用库HessianBurlap、基于JavaRMI的解决方案等等。Spring对不同的远端调用的实现封装基本上都采用了类似的模式来完成比如在客户端都是通过相关的ProxyFactoryBean和ClientInterceptor来完成的在服务器端是通过ServiceExporter来导出远端的服务对象的。有了这些统一的命名规则应用配置和使用远端调用会非常方便同时通过对这些Spring远端调用基础设施实现原理的分析还可以看到一些常用处理方法的技术实现比如对代理对象的使用、拦截器的使用、通过afterPropertiesSet来启动远端调用基础设施的建立等等这些都是在Spring中常用的技术。HTTP调用器客户端的实现在HtttpInvokerProxyFactory中设置了serviceProxy对象作为远端服务的本地代理对象同时在依赖注入完成以后通过afterPropertiesSet来对远端调用完成设置。Java代码HYPERLINK"http:wwwjavaeyecomtopic"o"复制代码"​ public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor  ​         implements FactoryBean<Object> {  ​     这是远端对象的代理  ​     private Object serviceProxy  ​   ​     Override  ​     在注入完成之后设置远端对象代理  ​     public void afterPropertiesSet() {  ​         superafterPropertiesSet()  ​         需要配置远端调用的接口  ​         if (getServiceInterface() == ) {  ​             throw new IllegalArgumentException("Property 'serviceInterface' is required")  ​         }这里使用ProxyFactory来生成远端代理对象注意这个this,因为HttpInvokerProxyFactoryBean的基类是HttpInvokerClientInterceptor所以代理类的拦截器被设置为HttpInvokerClientInterceptor  ​         thisserviceProxy = new ProxyFactory(getServiceInterface(), this)getProxy(getBeanClassLoader())  ​     }  ​   ​     FactoryBean生产对象的入口。返回的是serviceProxy对象这是一个代理对象  ​     public Object getObject() {  ​         return thisserviceProxy  ​     }  ​   ​     public Class<> getObjectType() {  ​         return getServiceInterface()  ​     }  ​   ​     public boolean isSingleton() {  ​         return true  ​     }  publicclassHttpInvokerProxyFactoryBeanextendsHttpInvokerClientInterceptorimplementsFactoryBean<Object>{这是远端对象的代理privateObjectserviceProxyOverride在注入完成之后设置远端对象代理publicvoidafterPropertiesSet(){superafterPropertiesSet()需要配置远端调用的接口if(getServiceInterface()==){thrownewIllegalArgumentException("Property'serviceInterface'isrequired")}这里使用ProxyFactory来生成远端代理对象注意这个this,因为HttpInvokerProxyFactoryBean的基类是HttpInvokerClientInterceptor所以代理类的拦截器被设置为HttpInvokerClientInterceptorthisserviceProxy=newProxyFactory(getServiceInterface(),this)getProxy(getBeanClassLoader())}FactoryBean生产对象的入口。返回的是serviceProxy对象这是一个代理对象publicObjectgetObject(){returnthisserviceProxy}publicClass<>getObjectType(){returngetServiceInterface()}publicbooleanisSingleton(){returntrue}可以看到为这个代理对象配置了一个拦截器HttpInvokerClientInterceptor在这个拦截器中拦截了对代理对象的方法调用。如以下代码所示:Java代码​ 对代理对象的方法调用入口  ​ public Object invoke(MethodInvocation methodInvocation) throws Throwable {  ​     if (AopUtilsisToStringMethod(methodInvocationgetMethod())) {  ​         return "HTTP invoker proxy for service URL "  getServiceUrl()  ""  ​     }  ​     创建RemoteInvocation对象这个对象封装了对远端的调用这些远端调用通过序列化的机制完成  ​     RemoteInvocation invocation = createRemoteInvocation(methodInvocation)  ​     RemoteInvocationResult result =   ​     try {  ​         这里是对远端调用的入口  ​         result = executeRequest(invocation, methodInvocation)  ​     }  ​     catch (Throwable ex) {  ​         throw convertHttpInvokerAccessException(ex)  ​     }  ​     try {返回远端调用的结果  ​         return recreateRemoteInvocationResult(result)  ​     }  ​     catch (Throwable ex) {  ​         if (resulthasInvocationTargetException()) {  ​             throw ex  ​         }  ​         else {  ​             throw new RemoteInvocationFailureException("Invocation of method "  methodInvocationgetMethod()   ​                     " failed in HTTP invoker remote service at "  getServiceUrl()  "", ex)  ​         }  ​     }  ​ }  对代理对象的方法调用入口publicObjectinvoke(MethodInvocationmethodInvocation)throwsThrowable{if(AopUtilsisToStringMethod(methodInvocationgetMethod())){return"HTTPinvokerproxyforserviceURL"getServiceUrl()""}创建RemoteInvocation对象这个对象封装了对远端的调用这些远端调用通过序列化的机制完成RemoteInvocationinvocation=createRemoteInvocation(methodInvocation)RemoteInvocationResultresult=try{这里是对远端调用的入口result=executeRequest(invocation,methodInvocation)}catch(Throwableex){throwconvertHttpInvokerAccessException(ex)}try{返回远端调用的结果returnrecreateRemoteInvocationResult(result)}catch(Throwableex){if(resulthasInvocationTargetException()){throwex}else{thrownewRemoteInvocationFailureException("Invocationofmethod"methodInvocationgetMethod()"failedinHTTPinvokerremoteserviceat"getServiceUrl()"",ex)}}}远端调用的具体实现过程是由executeRequest来完成的也就是在SimpleHttpInvokerRequestExecutor的实现中封装了整个HTTP调用器客户端实现的基本过程如下所示:Java代码​ 这是HTTP调用器实现的基本过程通过HTTP的request和reponse来完成通信在通信的过程中传输的数据是序列化的对象  ​ protected RemoteInvocationResult doExecuteRequest(  ​         HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)  ​         throws IOException, ClassNotFoundException {  ​     打开一个标准JSE HttpURLConnection  ​     HttpURLConnection con = openConnection(config)  ​     prepareConnection(con, baossize())  ​     远端调用封装成RemoteInvocation对象这个对象通过序列化被写到对应的HttpURLConnection中去  ​     writeRequestBody(config, con, baos)  ​     这里取得远端服务返回的结果然后把结果转换成RemoteInvocationResult返回  ​     validateResponse(config, con)  ​     InputStream responseBody = readResponseBody(config, con)  ​   ​     return readRemoteInvocationResult(responseBody, configgetCodebaseUrl())  ​ }  ​   ​ 把序列化对象输出到HttpURLConnection去  ​ protected void writeRequestBody(  ​         HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)  ​         throws IOException {  ​   ​     baoswriteTo(congetOutputStream())  ​ }  ​   ​ 为使用HttpURLConnection完成对象序列化需要进行一系列的配置  ​ 比如配置请求方式为post请求属性等等  ​ protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException {  ​     consetDoOutput(true)  ​     consetRequestMethod(HTTPMETHODPOST)  ​     consetRequestProperty(HTTPHEADERCONTENTTYPE, getContentType())  ​     consetRequestProperty(HTTPHEADERCONTENTLENGTH, IntegertoString(contentLength))  ​     LocaleContext locale = LocaleContextHoldergetLocaleContext()  ​     if (locale != ) {  ​         consetRequestProperty(HTTPHEADERACCEPTLANGUAGE, StringUtilstoLanguageTag(localegetLocale()))  ​     }  ​     if (isAcceptGzipEncoding()) {  ​         consetRequestProperty(HTTPHEADERACCEPTENCODING, ENCODINGGZIP)  ​     }  ​ }  ​ 获得HTTP响应的IO流  ​ protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)  ​         throws IOException {  ​     如果是通过gzip压缩那么需要先解压  ​     if (isGzipResponse(con)) {  ​          GZIP response found  need to unzip  ​         return new GZIPInputStream(congetInputStream())  ​     }  ​     else {  ​          Plain response found  ​          正常的HTTP响应输出  ​         return congetInputStream()  ​     }  ​ }  这是HTTP调用器实现的基本过程通过HTTP的request和reponse来完成通信在通信的过程中传输的数据是序列化的对象protectedRemoteInvocationResultdoExecuteRequest(HttpInvokerClientConfigurationconfig,ByteArrayOutputStreambaos)throwsIOException,ClassNotFoundException{打开一个标准JSEHttpURLConnectionHttpURLConnectioncon=openConnection(config)prepareConnection(con,baossize())远端调用封装成RemoteInvocation对象这个对象通过序列化被写到对应的HttpURLConnection中去writeRequestBody(config,con,baos)这里取得远端服务返回的结果然后把结果转换成RemoteInvocationResult返回validateResponse(config,con)InputStreamresponseBody=readResponseBody(config,con)returnreadRemoteInvocationResult(responseBody,configgetCodebaseUrl())}把序列化对象输出到HttpURLConnection去protectedvoidwriteRequestBody(HttpInvokerClientConfigurationconfig,HttpURLConnectioncon,ByteArrayOutputStreambaos)throwsIOException{baoswriteTo(congetOutputStream())}为使用HttpURLConnection完成对象序列化需要进行一系列的配置比如配置请求方式为post请求属性等等protectedvoidprepareConnection(HttpURLConnectioncon,intcontentLength)throwsIOException{consetDoOutput(true)consetRequestMethod(HTTPMETHODPOST)consetRequestProperty(HTTPHEADERCONTENTTYPE,getContentType())consetRequestProperty(HTTPHEADERCONTENTLENGTH,IntegertoString(contentLength))LocaleContextlocale=LocaleContextHoldergetLocaleContext()if(locale!=){consetRequestProperty(HTTPHEADERACCEPTLANGUAGE,StringUtilstoLanguageTag(localegetLocale()))}if(isAcceptGzipEncoding()){consetRequestProperty(HTTPHEADERACCEPTENCODING,ENCODINGGZIP)}}获得HTTP响应的IO流protectedInputStreamreadResponseBody(HttpInvokerClientConfigurationconfig,HttpURLConnectioncon)throwsIOException{如果是通过gzip压缩那么需要先解压if(isGzipResponse(con)){GZIPresponsefoundneedtounzipreturnnewGZIPInputStream(congetInputStream())}else{Plainresponsefound正常的HTTP响应输出returncongetInputStream()}}HTTP调用器服务器端的实现在服务器端使用SpringHTTP远端调用需要配置HttpInvokerServiceExporter作为远端服务的服务导出器来接收HTTP服务请求。在通过HTTP请求得到客户端传过来的RemoteInvocation对象以后就可以进行服务方法的调用了。服务调用需要的基本信息都封装在RemoteInvocation对象中。这个服务调用过程是由invokeAndCreateResult方法来实现的如RemoteInvocationSerializingExporter的invoke实现所示:Java代码​ protected Object invoke(RemoteInvocation invocation, Object targetObject)  ​         throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {  ​   ​     if (loggerisTraceEnabled()) {  ​         loggertrace("Executing "  invocation)  ​     }  ​     try {调用RemoteInvocationExecutor这个执行器是DefaultRemoteInvocationExecutor  ​         return getRemoteInvocationExecutor()invoke(invocation, targetObject)  ​     }  ​     catch (NoSuchMethodException ex) {  ​         if (loggerisDebugEnabled()) {  ​             loggerwarn("Could not find target method for "  invocation, ex)  ​         }  ​         throw ex  ​     }  ​     catch (IllegalAccessException ex) {  ​         if (loggerisDebugEnabled()) {  ​             loggerwarn("Could not access target method for "  invocation, ex)  ​         }  ​         throw ex  ​     }  ​     catch (InvocationTargetException ex) {  ​         if (loggerisDebugEnabled()) {  ​             loggerdebug("Target method failed for "  invocation, exgetTargetException())  ​         }  ​         throw ex  ​     }  ​ }  protectedObjectinvoke(RemoteInvocationinvocation,ObjecttargetObject)throwsNoSuchMethodException,IllegalAccessException,InvocationTargetException{if(loggerisTraceEnabled()){loggertrace("Executing"invocation)}try{调用RemoteInvocationExecutor这个执行器是DefaultRemoteInvocationExecutorreturngetRemoteInvocationExecutor()invoke(invocation,targetObject)}catch(NoSuchMethodExceptionex){if(loggerisDebugEnabled()){loggerwarn("Couldnotfindtargetmethodfor"invocation,ex)}throwex}catch(IllegalAccessExceptionex){if(loggerisDebugEnabled()){loggerwarn("Couldnotaccesstargetmethodfor"invocation,ex)}throwex}catch(InvocationTargetExceptionex){if(loggerisDebugEnabled()){loggerdebug("Targetmethodfailedfor"invocation,exgetTargetException())}throwex}}看到的invoke方法封装了服务器端调用的主体这个invoke方法在HttpInvokerServiceExporter的基类RemoteInvocationSerializingExporter中实现服务对象的方法调用完成之后会把调用结果通过HTTP响应和对象序列化传给HTTP调用器客户端从而完成整个HTTP调用器的远端调用过程如以下代码所示:Java代码​ protected void writeRemoteInvocationResult(  ​         HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)  ​         throws IOException {  ​ 设置Response的ContentType属性设置为applicationxjavaserializedobject  ​     responsesetContentType(getContentType())  ​     writeRemoteInvocationResult(request, response, result, responsegetOutputStream())  ​ }  ​ 输出到HTTP的Response然后把Response关闭  ​ protected void writeRemoteInvocationResult(  ​         HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)  ​         throws IOException {  ​   ​     ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os))  ​     try {  ​         doWriteRemoteInvocationResult(result, oos)  ​         oosflush()  ​     }  ​     finally {  ​         oosclose()  ​     }  ​ }  protectedvoidwriteRemoteInvocationResult(HttpServletRequestrequest,HttpServletResponseresponse,RemoteInvocationResultresult)throwsIOException{设置Response的ContentType属性设置为applicationxjavaserializedobjectresponsesetContentType(getContentType())writeRemoteInvocationResult(request,response,result,responsegetOutputStream())}输出到HTTP的Response然后把Response关闭protectedvoidwriteRemoteInvocationResult(HttpServletRequestrequest,HttpServletResponseresponse,RemoteInvocationResultresult,OutputStreamos)throwsIOException{ObjectOutputStreamoos=createObjectOutputStream(decorateOutputStream(request,response,os))try{doWriteRemoteInvocationResult(result,oos)oosflush()}finally{oosclose()}}经过这一系列的处理过程服务执行结果对象又回到了HTTP的远端调用客户端。在客户端从HTTP响应读取对象之后它把这个看起来像是在本地实现其实是由远端服务对象完成的调用结果交给发起远端调用的客户端调用方法从而最终完成整个远端调用的过程。这个过程很有特点它使用了HTTP的请求和响应作为通信通道在这个通信通道里面并没有再做进一步的附加的通信协议的封装而且在这个处理过程中使用的都是Java和Spring框架已有的特性比如通过IoC的配置以及代理对象拦截器的封装处理再加Java的序列化和反序列化以及在服务器端的SpringMVC框架的使用通过这些已有的技术实现让使用者感觉它的实现风格非常的简洁轻快整个代码实现阅读起来也让人感到非常的赏心悦目。spring事务探索spring自建事务管理模块。而且这个事务管理是一个抽象设计可以应用到很多场合包括普通的DataSourcejtajms和hibernate上。要正确使用spring的事务首先需要了解spring在事务设计上的一些概念统观spring事务围绕着两个核心PlatformTransactionManager和TransactionStatusPlatformTransactionManager直译过来就是平台相关事务这里的平台指的是“事务源”包括刚才我说的DataSourcejta等等。这些无一不是一个事务源。广义的说凡是可以完成事务性操作的对象都可以设计出相对应的PlatformTransactionManager只要这个事务源支持commitrollback和getTransaction语意。查看spring代码可以发现这些manager实现事务就是调用事务源的事务操作方法比如HibernateTransactionManagerJava代码​ protected void doCommit(DefaultTransactionStatus status) {  ​         HibernateTransactionObject txObject = (HibernateTransactionObject) statusgetTransaction()  ​         if (statusisDebug()) {  ​             loggerdebug("Committing Hibernate transaction on session "   ​                     txObjectgetSessionHolder()getSession()  "")  ​         }  ​         try {  ​             txObjectgetSessionHolder()getTransaction()commit()  ​         }  ​   ​   ​     }  protectedvoiddoCommit(DefaultTransactionStatusstatus){HibernateTransactionObjecttxObject=(HibernateTransactionObject)statusgetTransaction()if(statusisDebug()){loggerdebug("CommittingHibernatetransactiononsession"txObjectgetSessionHolder()getSession()"")}try{txObjectgetSessionHolder()getTransaction()commit()}}jdbc的DataSourceTransactionManagerJava代码​ protected void doCommit(DefaultTransactionStatus status) {  ​         DataSourceTransactionObject txObject = (DataSourceTransactionObject) statusgetTransaction()  ​         Connection con = txObjectgetConnectionHolder()getConnection()  ​         if (statusisDebug()) {  ​             loggerdebug("Committing JDBC transaction on connection "  con  "")  ​         }  ​         try {  ​             concommit()  ​         }  ​           ​     }  protectedvoiddoCommit(DefaultTransactionStatusstatus){DataSourceTransactionObjecttxObject=(DataSourceTransactionObject)statusgetTransaction()Connectioncon=txObjectgetConnectionHolder()getConnection()if(statusisDebug()){loggerdebug("CommittingJDBCtransactiononconnection"con"")}try{concommit()}}那么PlatformTransactionManager以什么依据处理事务呢?是TransactionStatus查看api发现这个接口有三个方法isNewTransaction()isRollbackOnly()setRollbackOnly()PlatformTransactionManager就是根据前两个方法决定是否要创建一个新事务是要递交还是回滚。至于第三个方法是改变事务当前状态的很多地方都要用到偏偏PlatformTransactionManager自身好像不怎么用毕竟事务状态的改变是由程序员代码决定的不需要一个manager多管闲事。总结上面所说的spring的事务由PlatformTransactionManager管理manager最后调用事务源的方法来实现一个事务过程。而manager通过TransactionStatus来决定如何实现。接下去说spring事务中的TransactionTemplate和TransactionInterceptorTransactionTemplate其实和spring中其他的template的作用类似起到化简代码的作用不要被它那么长的名字吓倒了事实上这个template并不是什么非常核心的对象。如果比较学究派的可以去看看template设计模式在此就不再对此赘述了。为什么要有TransactionTemplate?先来看看如果没有TransactionTemplate我们的代码该怎么写先来看看springreference中的一段代码Java代码​ DefaultTransactionDefinition def = new DefaultTransactionDefinition()  ​ defsetPropagationBehavior(TransactionDefinitionPROPAGATIONREQUIRED)  ​   ​ TransactionStatus status = transactionManagergetTransaction(def)  ​   ​ try {  ​      execute your business logic here  ​ } catch (MyException ex) {  ​     transactionManagerrollback(status)  ​     throw ex  ​ }  ​ transactionManagercommit(status)  DefaultTransactionDefinitiondef=newDefaultTransactionDefinition()defsetPropagationBehavior(TransactionDefinitionPROPAGATIONREQUIRED)TransactionStatusstatus=transactionManagergetTransaction(def)try{executeyourbusinesslogichere}catch(MyExceptionex){transactionManagerrollback(status)throwex}transactionManagercommit(status)这是直接使用transactionManager的例子可以看到真正执行businesslogic的地方是在try当中那段前后的代码都是为了完成事务管理的。如果每个businesslogic都要写上那么一段我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码Java代码​ public Object execute(TransactionCallback action) throws TransactionException {  ​         TransactionStatus status = thistransactionManagergetTransaction(this)  ​         Object result =   ​         try {  ​             result = actiondoInTransaction(status)  ​         }  ​         catch (RuntimeException ex) {  ​              transactional code threw application exception > rollback  ​             rollbackOnException(status, ex)  ​             throw ex  ​         }  ​         catch (Error err) {  ​              transactional code threw error > rollback  ​             rollbackOnException(status, err)  ​             throw err  ​         }  ​         thistransactionManagercommit(status)  ​         return result  ​     }  publicObjectexecute(TransactionCallbackaction)throwsTransactionException{TransactionStatusstatus=thistransactionManagergetTransaction(this)Objectresult=try{result=actiondoInTransaction(status)}catch(RuntimeExceptionex){transactionalcodethrewapplicationexception>rollbackrollbackOnException(status,ex)throwex}catch(Errorerr){transactionalcodethrewerror>rollbackrollbackOnException(status,err)throwerr}thistransactionManagercommit(status)returnresult}同上面的代码如出一辙前后是事务处理代码当中那段result=actiondoInTransaction(status)是我们的应用代码。至于action是什么全看各位的需要了。但是有一点要主要如果利用Transactio

类似资料

编辑推荐

Algorithms 4th Edition.pdf

《觉世与传世——梁启超的文学道路》夏晓虹着.中华书局.pdf

和刻本史记评林15册.pdf

红一方面军征战纪实.pdf

世界各国军事概况.pdf

职业精品

精彩专题

上传我的资料

精选资料

热门资料排行换一换

  • 钢结构疲劳.ppt

  • 电子陶瓷工艺原理.pdf

  • RADAR操作说明书.pdf

  • 子平基础概要(梁润湘).pdf

  • 商君书语(丁毅华).pdf

  • 鲁迅校《养生论·声无哀乐论》.p…

  • 秘传证治要诀及类方.pdf

  • 内经知要.PDF

  • 03ZG313中南建筑标准图集-…

  • 资料评价:

    / 94
    所需积分:1 立即下载

    意见
    反馈

    返回
    顶部