blazeds
Adobe和Spring于去年年底作了重要宣布,他们将在一个名为Spring BlazeDS Integration的联合项目中进行合作。 目的是允许将Spring开发模型用于通过Adobe Flex,BlazeDS,Spring和Java创建富Internet应用程序(RIA)。 这将允许Spring托管服务通过BlazeDS公开,而无需额外的配置文件。 其主要优点是,它使Spring易于使用,可以使用Flex,BlazeDS和Java创建应用程序。
在本文中,我将研究Spring BlazeDS Integration项目的变化,并展示其工作方式的示例。 首先看一下这将如何改变应用程序的连接方式,以及如何轻松地将现有的Spring项目转换为使用此新的集成项目。 我们结束了本项目的其他功能和优势。
整个过程中使用的示例应用程序是提供基本会计信息的简单苏打服务。 它使用的数据模型是代表客户帐户信息的SodaAccount。
当Spring发布时,它极大地改变了Java服务器端开发的完成方式。 它强调了使用依赖注入将简单的旧Java对象(POJO)连接在一起的用法。 这样简化了应用程序的开发和测试。
Spring的核心配置是使用JavaBeans完成的。 使用Bean,任何Java类都可以公开为服务。 例如,以下内容将Soda Service声明为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客户端的远程服务,集成项目使用Spring Web MVC。 Spring Web MVC使用DispatchServlet作为任何类型的HTTP请求或基于HTTP的远程服务的中央调度程序。 使用相同的JavaBeans配置机制配置Dispatch Servlet,以将请求转发到处理程序适配器以进行处理。
以前,BlazeDS项目将使用MessageBrokerServlet将请求路由到BlazeDS消息代理。 使用Spring BlazeDS可以将其替换为Spring Web MVC DispatchServlet。 然后将DispatchServlet配置为将HTTP消息转发到MessageBrokerHandlerAdapter。 该适配器被配置为Spring工厂bean。 它在Spring Web应用程序上下文中创建本地的BlazeDS Message Broker实例。 然后将其用于将Spring Bean导出为可直接从Flex客户端调用的远程服务。
这种配置BlazeDS Message Broker的方法允许与Spring项目进行更紧密的集成。 它还减少了将Spring Bean导出为远程服务的配置需求。 例如,以前,您必须在messages.xml中声明一个单独的条目才能导出Java服务。 现在,您只需在声明Spring Beans的同一文件中连接一个远程处理出口Bean。
Spring BlazeDS集成确实使用一些标准的BlazeDS XML配置文件来配置消息传递基础结构。 这包括诸如频道定义之类的内容。
该项目的下一个版本将添加与Spring Security的集成。 初始实现使用切入点顾问程序保护BlazeDS端点。 Pointcut Advisor是Spring Aspect Oriented Programming(AOP)支持的一部分。
无论您是要建立一个新项目,还是将支持添加到现有项目中,步骤都非常相似。 第一步是将所有需要的jar文件添加到您的库目录中。 您可以从Spring Source网站( http://www.springsource.org/spring-flex )下载它们,或使用示例项目库。
在此示例中,我们将使用一个简单的Soda Service项目并将其修改为使用Spring BlazeDS项目。 第一个更改是web.xml 。 在此文件中,所有对BlazeDS MessageBrokerServlet的引用均被删除。 而是使用对Spring DispatchServlet的引用:
<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映射模式将所有请求路由到Dispatcher Servlet。 它还指定了上下文配置以指向web-application-config.xml。
标准的BlazeDS文件位于WEB-INF / flex中。 主要文件是services-config.xml,它定义通道,日志记录和其他系统配置。 此文件中的一个更改是将标准AMF通道的URL更改为通过Dispatcher Servlet路由请求:
<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。 该bean映射了我们要处理的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。 然后,由于消息代理使用WEB-INF / flex / services-config.xml中的通道配置,因此发送到/ gorilla / messagebroker的消息将被路由到我们声明为服务的bean。
为了使消息代理现在了解我们的bean,配置的下一部分是声明应用程序Spring Beans并将其导出为远程服务。 在我们的示例中,我们将SodaService声明为sodaBean:
<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService"
init-method="initSodaAccounts">
<property name="numAccounts" value="1000"/>
</bean>/
然后将sodaBean暴露给BlazeDS远程处理:
<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设置公开的方法。
用于连接到服务器的客户端代码使用标准的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>
该远程对象允许Flex Client调用远程Java Server。 要让客户知道在哪个信道上发送呼叫,有两种选择。 第一种是根据服务器配置文件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。 该文件需要添加到Dispatcher Servlet上下文配置中,以便在启动时加载。 为此,我们将文件添加到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>
然后,在安全上下文文件中声明系统用户:
<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>
在服务器上设置安全性的第二部分是使用自定义安全性配置来配置消息代理。 为了允许Spring管理的消息代理配置有其他服务和/或安全性,它允许在MessageBrokerFactoryBean上设置其他配置处理器。 处理器实现两种方法,processBeforeStartup和processAfterStartup,它们允许在消息代理启动之前或之后设置配置。
为了配置消息代理的安全性,设置了两个过程。 第一个是提供身份验证和授权的登录命令,第二个是安全配置处理器,用于保护各个通道和URL。
LoginCommand是BlazeDS中用于定义自定义身份验证和授权过程的接口的名称。 然后,Bean SpringSecurityLoginCommand将Spring Security与BlazeDS安全性集成在一起,将对身份验证和授权的BlazeDS调用传递给Spring托管的安全上下文。 以下内容引用了先前定义的安全上下文,声明了此bean的实例:
<bean id="loginCommand"
class="org.springframework.flex.messaging.security.SpringSecurityLoginCommand">
<constructor-arg ref="_authenticationManager"/>
</bean>
第二个过程是安全配置处理器,被定义为切入点顾问,该切入点顾问定义了如何保护各个通道和URL。 切入点顾问是Spring AOP(面向方面的编程)的一部分,它定义在调用某些方法之前要调用的建议。 这实际上是过滤对远程服务的呼叫并阻止未经授权的呼叫。
在内部,BlazeDS使用AMF过滤器对消息调用执行预处理和后处理。 这些过滤器的工作方式与servlet过滤器类似,并且遵循标准的管道和过滤器设计模式。 这允许单个过滤器停止处理消息。 安全过程建议通道的AMF过滤器添加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>
接下来,我们定义一个端点源。 这将配置我们要保护的端点或通道,以及哪些角色可以访问它们。 对于示例,我们定义一个用户角色。 然后,我们配置一个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>
这样可以保护使用URL匹配** / protected / messagebroker / **的所有频道。 在样本中,这包括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托管消息代理的定义以使用以下配置处理器:
<bean id="mySpringManagedMessageBroker"
class="org.springframework.flex.messaging.MessageBrokerFactoryBean">
<property name="configProcessors">
<set>
<ref bean="loginCommand"/>
<ref bean="securityConfigProcessor"/>
</set>
</property>
</bean>
这将导致消息代理使用我们在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>
对于苏打水服务,我们定义了它只能通过安全通道进行通信。 这将阻止来自非正确身份角色的已验证用户的任何服务调用。
保护远程服务的客户端配置是一个简单得多的过程。 所有繁重的工作都在服务器端完成。 在客户端上,我们将远程对象定义更改为包括安全通道:
<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>
现在必须对远程对象进行身份验证,然后才能调用苏打水服务。 例如,如果我们不进行身份验证并调用苏打服务以获取苏打模型,则客户端将收到以下错误:
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集成项目通过使用Spring开发模型简化了Java中的Rich Internet Applications的开发。 通过提供与Spring Beans和Spring Security的集成,它简化了作为远程服务直接向Flex客户端公开和保护Java类的工作。 总体而言,该项目将极大地帮助开发使用Flex,BlazeDS和Java的企业应用程序。
Integration项目的将来版本将增加与Spring的进一步集成。 计划的功能包括集成以及与Spring Security和JMS的进一步集成。 还计划有一个自定义架构定义,用于定义服务器上的远程服务。 这将大大简化配置文件。
blazeds