Spring BlazeDS Integration 由 Adobe 與 SpringSource 合作開發,讓開發者以 Spring 程式模型 (DI、AOP、Security) 透過 BlazeDS 將 Spring Bean 直接暴露為 Flex 遠端服務,無需額外 BlazeDS 配置檔。本文涵蓋架構優勢、伺服器端/客戶端配置、Spring Security 整合保護服務完整實戰。
remoting-config.xml 維護MessageBrokerServlet,所有 HTTP/AMF 請求經 Spring MVC 分派下載 org.springframework.flex 相關 JAR,置於 WEB-INF/lib。
<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>
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="https://{server.name}:{server.port}/{context.root}/gorilla/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
<!-- MessageBrokerHandlerAdapter 處理 AMF 訊息 -->
<bean class="org.springframework.flex.messaging.servlet.MessageBrokerHandlerAdapter"/>
<!-- URL 映射至 Spring 管理的 MessageBroker -->
<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"/>
<!-- 業務 Bean -->
<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService" init-method="initSodaAccounts">
<property name="numAccounts" value="1000"/>
</bean>
<!-- 暴露為 Flex 遠端服務 -->
<bean id="sodaService" class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
<property name="messageBroker" ref="mySpringManagedMessageBroker"/>
<property name="service" ref="sodaBean"/>
</bean>
<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>
呼叫方式:remoteObject.getSodaModel(); 非同步回調處理 ResultEvent。
<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>
<bean id="loginCommand"
class="org.springframework.flex.messaging.security.SpringSecurityLoginCommand">
<constructor-arg ref="_authenticationManager"/>
</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>
<entry>
<key><value>my-protected-by-id-amf</value></key>
<ref bean="configAttribute"/>
</entry>
</map>
</constructor-arg>
</bean>
<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="mySpringManagedMessageBroker"
class="org.springframework.flex.messaging.MessageBrokerFactoryBean">
<property name="configProcessors">
<set>
<ref bean="loginCommand"/>
<ref bean="securityConfigProcessor"/>
</set>
</property>
</bean>
<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>
var token:AsyncToken = sodaChannels.login(username.text, password.text);
token.addResponder(new AsyncResponder(
function(result:ResultEvent, token:Object):void { remoteObject.getSodaModel(numAccounts.text); },
function(fault:FaultEvent, token:Object):void { ta.text += "Received fault: " + fault.fault + "\n"; }
));
<flex:remoting-destination>)