Spring和Flex之间通信的关键
近期由于需要做一个实时仪表盘的动态图表,于是开始研究Flex技术。
匆忙下载了FlexBuiler4,BlazeDS 3.2(用于和Java通讯),本机的Java开发环境为myeclipse6.0.1,eclipse 3.3。
在未使用Spring架构测试过程中一切都很顺利,Flex很容易就发现Web程序/WEB-INF/flex/remoting-config.xml中定义的服务。
<destination id="dataService"><properties><source>sample.service.DataService</source></properties></destination>
sample.service.DataService为我写好的数据提供服务类。
当我在引入Spring注解标签注册Bean取得DAO对象时的就出现了问题。在Flex中测试服务时提示找不到服务的错误。想了下可能是由于Flex在和Java通讯时取得的服务实例并不是通过Spring注册的Bean的实例。
如何获取上下文中定义的bean呢?
ApplicationContext中有个getBean(String beanName)方法,可以通过Bean的名字取得对应Bean的实例。准备着手写的时候,我在网上发现了Jeff Vroom这位达人实现的FlexFactory接口的一个类。
SpringFactory.java
package flex.samples.factories;import org.springframework.context.ApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import org.springframework.beans.BeansException;import org.springframework.beans.factory.NoSuchBeanDefinitionException;import flex.messaging.FactoryInstance;import flex.messaging.FlexFactory;import flex.messaging.config.ConfigMap;import flex.messaging.services.ServiceException;public class SpringFactory implements FlexFactory{ private static final String SOURCE = "source"; public void initialize(String id, ConfigMap configMap) {} /** * 创建Flex引用的实例 **/ public FactoryInstance createFactoryInstance(String id, ConfigMap properties) { SpringFactoryInstance instance = new SpringFactoryInstance(this, id, properties); instance.setSource(properties.getPropertyAsString(SOURCE, instance.getId())); return instance; } // end method createFactoryInstance() public Object lookup(FactoryInstance inst) { SpringFactoryInstance factoryInstance = (SpringFactoryInstance) inst; return factoryInstance.lookup(); } static class SpringFactoryInstance extends FactoryInstance { SpringFactoryInstance(SpringFactory factory, String id, ConfigMap properties) { super(factory, id, properties); } public String toString() { return "SpringFactory instance for id=" + getId() + " source=" + getSource() + " scope=" + getScope(); } /** * 通过Bean Id查找上下文取得对应Bean的实例 */ public Object lookup() { ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(flex.messaging.FlexContext.getServletConfig().getServletContext()); String beanName = getSource(); try { return appContext.getBean(beanName); } catch (NoSuchBeanDefinitionException nexc) { ServiceException e = new ServiceException(); String msg = "Spring service named '" + beanName + "' does not exist."; e.setMessage(msg); e.setRootCause(nexc); e.setDetails(msg); e.setCode("Server.Processing"); throw e; } catch (BeansException bexc) { ServiceException e = new ServiceException(); String msg = "Unable to create Spring service named '" + beanName + "' "; e.setMessage(msg); e.setRootCause(bexc); e.setDetails(msg); e.setCode("Server.Processing"); throw e; } } } } 导入程序后,在WEB-INF/flex/services-config.xml文件中追加如下内容:
<factories> <factory id="spring" /></factories>
然后再sample.service.DataService中添加@Service注释标签,如果应用中没有启用注解功能直接在spring配置文件applicationContext.xml中新增dataService的注册信息:
<beans> <bean name="dataService" singleton="true"/> </beans>
最后,修改下/WEB-INF/flex/remoting-config.xml文件中dataService的注册信息:
<destination id="dataService"> <properties> <factory>spring</factory> <source>dataService</source> </properties> </destination>
Flex 4中我尝试了下导入,几次都不成功。看来只能手工写了,取得服务的代码如下:
<mx:RemoteObject id="dataService" destination="dataService"/>
其中destination="dataService"为/WEB-INF/flex/remoting-config.xml中定义的dataService,不要搞错了哦。
调用服务的方法:
<mx:Script><![CDATA[protected function clickMe(event:MouseEvent):void{dataService.getRequest(dataRequest.text);dataService.addEventListener(ResultEvent.RESULT,getResult);}protected function getResult(event:ResultEvent):void{var s:String= event.result as String;trace(s);}]]></mx:Script><mx:TextInput id="dataRequest"/><mx:Button label="Request" click="clickMe(event)" />重新发布应用程序,OK!
总结:当使用Spring作为Web应用管理容器时,在系统启动的时候就会通过setter方法自动注入Bean的实例信息。我们在程序中动态创建实例时并没有被注入实例信息,需要手动注入实例信息。