程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Spring BlazeDS Integration簡介與入門

Spring BlazeDS Integration簡介與入門

編輯:關於JAVA

去年底Adobe與Spring共同宣布將聯合開發一個新項目:Spring BlazeDS Integration。其目標是:開發者可以利用Spring開發模型通過Adobe Flex、BlazeDS、Spring以及Java技術創建RIA。這樣我們就可以通過BlazeDS公開Spring管理的服務而無需額外的配置文件。其優勢在於將Spring的易用性與Flex、BlazeDS以及Java整合起來以共同創建應用。

我將在本文中介紹Spring BlazeDS Integration項目對傳統開發方式有哪些改觀,同時展示一些相關示例。首先,我們一起來看看它是如何改變應用的集成方式以及如何對現有的 Spring項目進行轉換使之可以利用新的集成。最後我將對該項目的其他特性以及優勢進行適當的介紹。

以Spring的方式開發RIA

Spring的橫空出世完全顛覆了傳統Java服務端的開發方式。它鼓勵通過依賴注入的方式來裝配POJO,這極大地簡化了應用的開發與測試。

Spring的核心配置是通過Java bean實現的。借助於bean,任何Java類都能被公開成為服務。比如說,下面的配置片段就將Soda服務聲明為一個Spring bean:

<!-- Implementation of soda bean-->
<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService" init-method="initSodaAccounts">
  <property name="numAccounts" value="1000"/>
</bean>

為了將這些bean公開成為Flex客戶端所用的遠程服務,Integration項目采用了Spring Web MVC。Spring Web MVC將DispatcherServlet作為一個中央分發器,用以處理任何類型的HTTP請求或是基於HTTP的遠程服務。我們可以通過相同的 JavaBean配置方式來配置該DispatcherServlet以將請求轉發給相應的處理器進行後續處理。

之前,BlazeDS項目會通過MessageBrokerServlet將請求路由給相應的BlazeDS Message Broker。現在借助於Spring BlazeDS,Spring Web MVC DispatcherServlet已經替代了MessageBrokerServlet,接下來就需要配置DispatcherServlet以將請求轉發給MessageBrokerHandlerAdapter。 該適配器本身是個Spring工廠bean,它會在Spring Web應用上下文中創建一個局部BlazeDS Message Broker實例,然後將Spring bean公開成為遠程服務,之後Flex客戶端就能夠直接調用該服務了。

這種配置BlazeDS Message Broker的方式可以與Spring項目結合的更加緊密,同時還減少了將Spring bean公開成遠程服務所需的配置量。比如說之前,我們需要在messaging.xml中聲明一個單獨的條目來公開Java服務,但現在可以輕松地在聲明Spring bean的那個配置文件中公開遠程bean。

Spring BlazeDS Integration也使用了一些標准的BlazeDS XML配置文件來配置消息基礎設施。這包括通道定義等一些內容。

該項目的下一版本將要增加與Spring Security的集成。最初的實現會通過一個pointcut advisor來保護BlazeDS端點。Pointcut advisor是Spring AOP支持的一部分。

建立全新的Spring BlazeDS Integration項目——服務器端

無論是建立全新的項目還是為現有的項目增加支持,步驟都是大同小異的。第一步需要將所需的jar文件增加到程序庫目錄中。可以通過Spring Source站點(http://www.springsource.org/spring-flex))下載,也可以使用示例項目中的程序庫。

對於這個示例來說,我們打算將一個簡單的Soda Service項目修改為Spring BlazeDS項目。首先要修改web.xml文件。將該文件中所有對BlazeDS MessageBrokerServlet的引用都刪掉,然後加上對Spring DispatcherServlet的引用:

<servlet>
  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/config/web-application-config.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

   <servlet-mapping>
     <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
     <url-pattern>/gorilla/*</url-pattern>
   </servlet-mapping>

以上配置通過標准的Servlet映射模式將所有的請求路由給DispatcherServlet,同時還將上下文配置信息指定為web-application-config.xml。

標准的BlazeDS文件位於WEB-INF/flex中,其主文件為services-config.xml,其中定義了通道、日志及其他系統配置。該文件的一個變化就是標准AMF通道的URL變成通過DispatcherServlet來路由請求:

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
  <endpoint url="http://{server.name}:{server.port}/{context.root}/
   gorilla/messagebroker/amf"
   class="flex.messaging.endpoints.AMFEndpoint"/>

web-application-config.xml是主配置文件。事實上,一旦配置好了其他文件,那麼在大多數情況下只需要修改該文件就行了。在 web-application-config.xml文件中聲明了MessageBrokerHandlerAdapter,這樣就會將HTTP消息路由給Spring管理的Message Broker。

<bean class="org.springframework.flex.messaging.servlet.MessageBrokerHandlerAdapter"/>

文件中聲明的框架的另一部分是MessageBrokerFactoryBean。它對我們想處理的URL進行了映射,也就是發往Dispatch Servlet的所有請求:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="mappings">
  <value>
   /*=mySpringManagedMessageBroker 
  </value>
  </property>
</bean>

<bean id="mySpringManagedMessageBroker" class="org.springframework.flex.messaging.MessageBrokerFactoryBean"/>

由於DispatcherServlet監聽著/gorilla路徑,因此該配置會將發送給/gorilla URL的所有請求都傳給Spring管理的MessageBroker。然後由於Message Broker使用了WEB-INF/flex/services-config.xml外的通道配置,這樣發送給/gorilla /messagebroker的消息就會被路由給聲明為服務的那些bean了。

這樣,Message Broker就與bean發生了聯系,下一步配置就是聲明應用中的Spring bean並將其公開成為遠程服務。在該示例中,我們將SodaService聲明為sodaBean:

<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService"
  init-method="initSodaAccounts">
  <property name="numAccounts" value="1000"/>
</bean>

接下來,為BlazeDS remoting公開sodaBean:

<bean id="sodaService" class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
  <property name="messageBroker" ref="mySpringManagedMessageBroker"/>
  <property name="service" ref="sodaBean"/>
</bean>

上面的配置引用了之前的Message Broker bean來公開sodaBean。默認情況下,類中所有方法都會被公開成為遠程服務。FlexRemotingServiceExporter擁有眾多選項來對服務進行配置。比如說,我們可以通過includeMethods和excludeMethods來選擇公開或是不公開哪些方法。

建立全新的Spring BlazeDS Integration項目——客戶端

用於連接服務器的客戶端代碼使用了標准的Flex RemoteObjects。對於該示例應用,我們聲明了如下的RemoteObject:

<mx:RemoteObject id="remoteObject"
  destination="sodaService"
  result="resultHandler(event);"
  fault="faultHandler(event);"
  channelSet="{sodaChannels}"/>

<mx:ChannelSet id="sodaChannels">
  <mx:AMFChannel uri="/gorilla/messagebroker/amf"/>
</mx:ChannelSet>

憑借該remote對象,Flex客戶端可以調用遠程的Java服務器。有兩種手段能讓客戶端知道該向哪個通道發起調用。其一是針對服務端配置文件 services-config.xml來編譯客戶端,通常這不是一個好辦法,因為它將客戶端與服務器端緊密耦合在了一起。其二是通過一個通道集將通道配置在客戶端上。

對RemoteObject的調用與本地對象調用大同小異,區別在於返回結果的過程是異步的。基於這個原因聲明了一個resultHandler以在服務端的結果返回時進行回調。在本示例中,對服務器端的調用形式如下:

remoteObject.getSodaModel();

返回的結果是個ResultEvent,然後將其轉換為sodaModel:

sodaModel = event.result as SodaModel;

保護遠程服務——服務器端

為了保護與服務器端的通信,Spring BlazeDS Integration項目使用了一個客戶化的認證和授權過程。該過程將Spring Security與BlazeDS安全過程集成起來了(注意,在本文撰寫之際,該處所使用的代碼僅僅存在於SVN上。同時我將示例所用代碼的快照放到了 jar文件中)。

在服務器端進行安全配置的第一步就是定義安全上下文。這需要為用戶定義用戶名、密碼以及相關角色等信息。在該簡單示例中,我們僅僅將用戶信息定義在文件中。真實的企業項目很可能會將這些信息放到數據庫中或是使用單點登錄。

我們通過一個單獨的配置文件(security-context.xml)來聲明系統中的用戶。需要將該文件加到DispatcherServlet上下文配置中以便服務器啟動時就能對其進行加載。如下配置片段展示了如何在web.xml文件中配置該文件:

<servlet>
  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</
   servlet-class>
  <init-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/config/security-context.xml
   /WEB-INF/config/web-application-config.xml
  </param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>

接下來,在security-context.xml文件中聲明系統用戶:

<authentication-provider>
  <user-service>
  <user name="ryan" password="monkey"
  authorities="ROLE_USER, ROLE_ADMIN" />
  <user name="alex" password="chimp" authorities="ROLE_USER" />
  </user-service>
</authentication-provider>

第二步就是通過客戶化的安全配置文件來配置Message Broker。為了將額外的服務或是安全配置到Spring管理的Message Broker上,我們需要對MessageBrokerFactoryBean增加一些額外的配置處理器。該處理器實現了兩個方法:processBeforeStartup及processAfterStartup,它們可以在Message Broker的啟動前後為其設定相關的配置。

要想配置Message Broker的安全信息,我們需要設定兩個處理器。其一是登錄命令,它提供了認證與授權;其二是一個安全配置處理器,它保護個別的通道與URL。

LoginCommand是BlazeDS中的一個接口名,它用於定義客戶化的認證與授權過程。接下來,SpringSecurityLoginCommand bean就將Spring Security與BlazeDS security集成起來,將BlazeDS發出的進行認證與授權的調用傳遞給Spring管理的安全上下文。下面的代碼片段聲明了該bean的一個實例並引用了之前定義的安全上下文:

<bean id="loginCommand"
   class="org.springframework.flex.messaging.security.SpringSecurityLoginCommand">
  <constructor-arg ref="_authenticationManager"/>
</bean>

第二個過程需要定義一個安全配置處理器以作為pointcut advisor,它定義了保護每個通道及URL的機制。pointcut advisor是Spring AOP的一部分,定義了在某個方法調用之前需要調用的advice。本質上,它會過濾對遠程服務的調用然後阻止未授權的調用。

BlazeDS在內部通過AMF Filter來執行消息調用的預處理與後續處理。這些Filter的工作方式類似於Servlet Filter並遵循著標准的pipe-and-filter設計模式。這樣,每個Filter都能阻止對消息的進一步處理。該安全過程會通知通道的AMF Filter來增加Spring管理的安全。

為了定義安全處理器,首先需要向WEB-INF/flex/services-config.xml文件中添加兩個額外的通道。

<channel-definition id="my-protected-amf"
    class="mx.messaging.channels.AMFChannel">
  <endpoint url="http://{server.name}:{server.port}/{context.root}/
    gorilla/protected/messagebroker/amf"
    class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

<channel-definition id="my-protected-by-id-amf"
    class="mx.messaging.channels.AMFChannel">
  <endpoint url="http://{server.name}:{server.port}/{context.root}/
     gorilla/protected2/messagebroker/amf"
    class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

接下來我們定義一個端點源(endpoint source),它配置了需要保護的端點或通道以及訪問它們所需的角色。對於本示例來說,我們只定義一種用戶角色,然後配置一個需要保護的URL及端點:

<bean id="configAttribute"
   class="org.springframework.security.ConfigAttributeDefinition">
  <constructor-arg type="java.lang.String" value="ROLE_USER"/>
</bean>

<bean id="endpointSource"
  class="org.springframework.flex.messaging.security.EndpointDefinitionSource">
  <constructor-arg>
    <bean class="org.springframework.security.util.AntUrlPathMatcher"/>
  </constructor-arg>
  <constructor-arg>
  <map>
   <entry>
   <key>
    <bean class="org.springframework.security.intercept.web.RequestKey">
    <constructor-arg value="**/protected/
      messagebroker/**"/>
    </bean>
   </key>
   <ref bean="configAttribute"/>
   </entry>
  </map>
  </constructor-arg>
  <constructor-arg>
  <map>
   <entry>
   <key>
    <value>my-protected-by-id-amf</value>
   </key>
   <ref bean="configAttribute"/>
   </entry>
  </map>
  </constructor-arg>
</bean>

以上配置保護了匹配於**/protected/messagebroker/**路徑的URL。在本示例中,這包括了my-protected- amf(該通道監聽/gorilla/protected/messagebroker/amf)與my-protected-by-id-amf通道。

接下來,我們定義端點攔截器與異常解析器以將所有配置連接在一起:

<bean id="endpointInterceptor"

   class="org.springframework.flex.messaging.security.EndpointServiceMessagePointcutAdvisor">
  <constructor-arg>
  <bean class="org.springframework.flex.messaging.security.EndpointInterceptor">
   <property name="accessDecisionManager" ref="_accessManager"/>
   <property name="authenticationManager" ref="_authenticationManager"/>
   <property name="objectDefinitionSource" ref="endpointSource"/>
  </bean>
  </constructor-arg>
</bean>

<bean id="exceptionTranslator" class="org.springframework.flex.messaging.security.EndpointServiceMessagePointcutAdvisor">
  <constructor-arg>
  <bean class="org.springframework.flex.messaging.security.SecurityExceptionTranslationAdvice"/>
  </constructor-arg>
</bean>

上面的代碼配置了端點攔截器以將訪問與認證管理器應用到端點源上。

最後,我們修改Spring管理的Message Broker的定義來應用這些配置處理器:

<bean id="mySpringManagedMessageBroker"
  class="org.springframework.flex.messaging.MessageBrokerFactoryBean">
<property name="configProcessors">
  <set>
  <ref bean="loginCommand"/>
  <ref bean="securityConfigProcessor"/>
  </set>
</property>
</bean>

這樣,Message Broker就會通過配置在security-context.xml文件中的安全上下文來保護定義在端點攔截器中的通道。現在如果要定義服務,那還需要定義服務通信所需的通道。

<bean id="sodaService" class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
  <property name="messageBroker" ref="mySpringManagedMessageBroker"/>
  <property name="service" ref="sodaBean"/>
  <property name="channelIds" value="my-protected-amf,
  my-protected-by-id-amf"/>
</bean>

對於該soda服務來說,我們已經定義好了其只能在安全的通道上進行通信。這會阻止未認證的用戶(並非來自於正確的角色)對該服務的訪問。

保護遠程服務——客戶端

安全的遠程服務的客戶端配置相當簡單。所有的重頭戲都在服務端完成了。在客戶端,我們只需修改remote object定義使之包含一個安全的通道即可:

<mx:RemoteObject id="remoteObject"
  destination="sodaService"
  result="resultHandler(event);"
  fault="faultHandler(event);"
  channelSet="{sodaChannels}"/>

<mx:ChannelSet id="sodaChannels">
  <mx:AMFChannel uri="/gorilla/protected/messagebroker/amf"/>
</mx:ChannelSet>

現在,remote object必須要經過認證方能對soda服務進行調用。比如說,如果我們沒有認證,同時又調用了soda服務來獲取Soda模型,那麼客戶端就會收到如下的錯誤消息:

 

Received fault: [RPC Fault faultString="An Authentication object was not found in theB
SecurityContext" faultCode="Client.Authentication" faultDetail="null"]

我們只需將登陸信息傳遞給管道集就能實現對客戶端的認證。如下是個超級簡單的示例:

var token:AsyncToken = sodaChannels.login(username.text, password.text);
token.addResponder(
  new AsyncResponder(
  function(result:ResultEvent, token:Object = null):void{
   remoteObject.getSodaModel(numAccounts.text);
  },
  function(result:FaultEvent, token:Object = null):void{
   ta.text += "Received fault: " + result.fault + "\n";
  }
  )
  );

以上代碼會從用戶名與密碼框中獲取登陸信息並對用戶進行認證。如果認證成功,那麼就會調用遠程服務並返回Soda模型。

小結

Spring BlazeDS Integration項目通過使用Spring開發模型簡化了Java RIA的開發。通過與Spring Bean及Spring Security的集成,它可以輕松實現將遠程服務直接公開給Flex客戶端的過程。總體上來說,該項目主要面向使用Flex、BlazeDS及Java 的企業級應用開發。

Integration項目的未來版本會進一步增強與Spring的集成。計劃的特性包括與Spring Security及JMS的進一步集成。同時還有一個用於定義服務端上遠程服務的客戶化模式定義。這將極大地簡化配置文件的編寫。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved