您的位置:首页 > 编程语言 > Java开发

flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程。

2011-09-19 11:08 876 查看
实现目标:java做后台service,每隔300毫秒,生成一个uuid,以 testJob做为订阅关键词,发布给所有订阅此关键词的flex客户端。

配置过程和源码:

1.修改blazeds自动生成的WEB-INF/flex/services-config.xml文件。由于原来没有polling-amf的定义,所以需要加入。代码如下:

view plain

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service-include file-path="remoting-config.xml" />
<service-include file-path="proxy-config.xml" />
<service-include file-path="messaging-config.xml" />
</services>
<security>
<login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat"/>
<!-- Uncomment the correct app server
<login-command class="flex.messaging.security.TomcatLoginCommand" server="JBoss">
<login-command class="flex.messaging.security.JRunLoginCommand" server="JRun"/>
<login-command class="flex.messaging.security.WeblogicLoginCommand" server="Weblogic"/>
<login-command class="flex.messaging.security.WebSphereLoginCommand" server="WebSphere"/>
-->
<!--
<security-constraint id="basic-read-access">
<auth-method>Basic</auth-method>
<roles>
<role>guests</role>
<role>accountants</role>
<role>employees</role>
<role>managers</role>
</roles>
</security-constraint>
-->
</security>
<channels>
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
<channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
<endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
</properties>
</channel-definition>
<channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>4</polling-interval-seconds>
</properties>
</channel-definition>

<channel-definition id="my-longpolling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amflongpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>5</polling-interval-seconds>
<wait-interval-millis>60000</wait-interval-millis>
<client-wait-interval-millis>1</client-wait-interval-millis>
<max-waiting-poll-requests>200</max-waiting-poll-requests>
<user-agent-settings>
<!-- MSIE 5, 6, 7 default max number of permanent HTTP connections is 2. -->
<user-agent match-on="MSIE" max-streaming-connections-per-session="1"/>
<!-- MSIE 8 max number is 6. -->
<user-agent match-on="MSIE 8" max-streaming-connections-per-session="5"/>
<!-- Firefox 1, 2 max number is 2. -->
<user-agent match-on="Firefox" max-streaming-connections-per-session="1"/>
<!-- Firefox 3 max number is 6. -->
<user-agent match-on="Firefox/3" max-streaming-connections-per-session="5"/>
<!-- Safari 3, 4 max number is 4. -->
<user-agent match-on="Safari" max-streaming-connections-per-session="3"/>
<!-- Chrome 0, 1, 2 max number is 6. -->
<user-agent match-on="Chrome" max-streaming-connections-per-session="5"/>
<!-- Opera 7, 9 max number is 4.-->
<user-agent match-on="Opera" max-streaming-connections-per-session="3"/>
<!-- Opera 8 max number is 8. -->
<user-agent match-on="Opera 8" max-streaming-connections-per-session="7"/>
<!-- Opera 10 max number is 8. -->
<user-agent match-on="Opera 10" max-streaming-connections-per-session="7"/>
</user-agent-settings>
</properties>
</channel-definition>

<channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
</channel-definition>
<!--
<channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/>
</channel-definition>
<channel-definition id="my-secure-http" class="mx.messaging.channels.SecureHTTPChannel">
<endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/httpsecure" class="flex.messaging.endpoints.SecureHTTPEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
</properties>
</channel-definition>
-->
</channels>
<logging>
<target class="flex.messaging.log.ConsoleTarget" level="Error">
<properties>
<prefix>[BlazeDS] </prefix>
<includeDate>false</includeDate>
<includeTime>false</includeTime>
<includeLevel>false</includeLevel>
<includeCategory>false</includeCategory>
</properties>
<filters>
<pattern>Endpoint.*</pattern>
<pattern>Service.*</pattern>
<pattern>Configuration</pattern>
</filters>
</target>
</logging>
<system>
<redeploy>
<enabled>false</enabled>
<!--
<watch-interval>20</watch-interval>
<watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>
<watch-file>{context.root}/WEB-INF/flex/proxy-config.xml</watch-file>
<watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>
<watch-file>{context.root}/WEB-INF/flex/messaging-config.xml</watch-file>
<watch-file>{context.root}/WEB-INF/flex/data-management-config.xml</watch-file>
<touch-file>{context.root}/WEB-INF/web.xml</touch-file>
-->
</redeploy>
</system>
</services-config>

2.在spring的配置文件中定义 defaultMessageTemplate class="org.springframework.flex.messaging.MessageTemplate"

view plain

<bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />

之所以要定义这个bean,是为了在做service的时候。可以用注解@Autowired来引入这个MessageTemplate的实例。

3.在web.xml中定义spring和flex的集成。这个配置是使用spring和flex集成时候的配置,和push技术无关。

view plain

<!-- 定义 spring flex 集成的配置,使用单独的配置文件。
不使用在一个applicatonContext.xml中import springFlex.xml的方法
spring flex 一定要用DispatcherServlet 方法。不能用ContextLoaderListener -->
<servlet>
<servlet-name>MessagebrokerServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/META-INF/springFlex.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map /spring/* requests to the DispatcherServlet -->
<servlet-mapping>
<servlet-name>MessagebrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
<!-- 定义 spring flex 集成的配置 结束-->

<!-- 访问RDS 定义开始-->
<servlet>
<servlet-name>RDSDispatchServlet</servlet-name>
<servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>
<init-param>
<param-name>useAppserverSecurity</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>messageBrokerId</param-name>
<param-value>_messageBroker</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping id="RDS_DISPATCH_MAPPING">
<servlet-name>RDSDispatchServlet</servlet-name>
<url-pattern>/CFIDE/main/ide.cfm</url-pattern>
</servlet-mapping>
<!-- 访问RDS 定义结束 -->

4.由于web.xml配置中引入了WEB-INF/classes/META-INF/springFlex.xml这个文件,所以在springFlex.xml文件中进行详细配置

5.springFlex.xml文件如下,主要是定义flex:message-destination ,既是监听的数据的关键词

view plain

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:flex="http://www.springframework.org/schema/flex"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/flex http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">
<flex:message-broker>
<flex:message-service
default-channels="my-polling-amf" />
</flex:message-broker>

<flex:message-destination id="simple-feed" />
<flex:message-destination id="testJob-feed"/>

</beans>

6.编写后台推送的java service bean:

view plain

/***********************************************************************
*
* TestJob.java
*
* ****所有,
* 受到法律的保护,任何公司或个人,未经授权不得擅自拷贝。
* @copyright Copyright: 2000-2011
* @creator 徐泽宇 <br/>
* @create-time 2011-6-27 下午11:51:16
* @revision $Id: *
***********************************************************************/
package com.alcor.test.service.quartz;
import java.util.Date;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.flex.messaging.MessageTemplate;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.flex.remoting.RemotingInclude;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import flex.messaging.messages.AsyncMessage;
@Service
@RemotingDestination
public class TestJob {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(TestJob.class);
@Autowired
MessageTemplate template;

private static FeedThread thread;

@RemotingInclude
public void work3 (){
if (thread == null) {
thread = new FeedThread(template);
thread.start();
}
}

public static class FeedThread extends Thread {
public boolean running = false;
private final MessageTemplate template;
public FeedThread(MessageTemplate template) {
this.template = template;
run();
}
@Override
public void run() {
this.running = true;
while (this.running) {
logger.debug("testJob-feed send");
this.template.send("testJob-feed", UUID.randomUUID().toString());
// this.template.send("testJob-feed", UUID.randomUUID().toString());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
}
}

注意:这里使用了@Service,@@RemotingDestination 注解和 @Autowired MessageTemplate template; 这样就避免了在spring中利用配置文件进行定义bean。

如果要使用spring 配置文件来定义。可以参考下面代码(来自blazeds的官方例子中的spring配置文件)

view plain

<!-- MessageTemplate makes it easy to publish messages -->
<bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />
<!-- Pojo used to start and stop the data feed that pushes data in the 'simple-feed' destination -->
<bean id="simpleFeedStarter" class="org.springframework.flex.samples.simplefeed.SimpleFeed">
<constructor-arg ref="defaultMessageTemplate" />
<flex:remoting-destination />
</bean>

具体的业务实现是在 内联线程类FeedThread 里面的run()中实现。

这要做的目标是为了让这个线程启动,是一定要通过flex的一个客户端连上来,才能启动。而不能随着spring context启动而启动。否则会报告messageBroke没有设置在flexContext之类的错误。

那么:如果我们想后台在没有任何一个客户端连上来的情况下,也要启动这个发送服务应该如何做?

典型场景: 后台web应用启动,并且定义了一个定时器。每隔 5s 进行一个逻辑处理,然后把处理结果发送给前台 flex(无论是否有felx客户端连上)

这就需要用下面代码:

view plain

public String work2(){
if (logger.isDebugEnabled()) {
logger.debug("work2() - start"); //$NON-NLS-1$
}
String m_rtn ="Spring 的TestJob任务work2被调用!" ;

String returnString =new Date().toLocaleString()+ m_rtn;
//------------------------------------------
MessageBroker msgBroker = MessageBroker.getMessageBroker("_messageBroker");
AsyncMessage am = new AsyncMessage();
am.setDestination("testJob-feed");
//am.setHeader("DSSubtopic", "tick");
am.setClientId(UUID.randomUUID().toString());
String msgID =UUID.randomUUID().toString();
//System.out.println("MESSAGE ID:" + msgID);
am.setMessageId(msgID);
am.setTimestamp(System.currentTimeMillis());
am.setBody(returnString);
if (msgBroker != null)
{
msgBroker.routeMessageToService(am, null);
}
//------------------------------------------

if (logger.isDebugEnabled()) {
logger.debug("work2() - end"); //$NON-NLS-1$
}
return returnString;
}

这个work2 方法可以通过 quartz或者spring 的@Scheduled注解来进行定时器调用。

主要的关键代码是

MessageBroker msgBroker = MessageBroker.getMessageBroker("_messageBroker");

这个就是获得一个 _messageBroker的实例。"_messageBroker"字符串是由 <flex:message-broker > 标签中的id来指定。

如果没有id 指定,则缺省使用 “"_messageBroker"”这个字符串

7.前台的订阅flex程序:

view plain

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">

<fx:Script>
<!--[CDATA[
import mx.controls.Alert;
import mx.messaging.messages.IMessage;

private function messageHandler(message:IMessage):void
{
pushedValue.text = ""+ message.body;
}

private function messageHandler1(message:IMessage):void
{
pushedValue1.text = ""+ message.body;
}

]]-->
</fx:Script>

<fx:Declarations>
<s:ChannelSet id="cs">
<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>
<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>
<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>
</s:ChannelSet>

<mx:Consumer id="consumer" destination="simple-feed" channelSet="{cs}"
message="messageHandler(event.message)"/>
<mx:Consumer id="consumer1" destination="testJob-feed" channelSet="{cs}"
message="messageHandler1(event.message)"/>
</fx:Declarations>
<s:HGroup>
<s:Group>
<s:TextInput id="pushedValue" width="250" verticalCenter="0" horizontalCenter="0"/>
<s:Button label="spimle-feed 订阅" click="consumer.subscribe()" enabled="{!consumer.subscribed}" verticalCenter="30" horizontalCenter="-50"/>
<s:Button label="Unsubscribe" click="consumer.unsubscribe()" enabled="{consumer.subscribed}" verticalCenter="30" horizontalCenter="50"/>
</s:Group>
<s:Group>
<s:TextInput id="pushedValue1" width="250" verticalCenter="0" horizontalCenter="0"/>
<s:Button label="testJob 订阅" click="consumer1.subscribe()" enabled="{!consumer1.subscribed}" verticalCenter="30" horizontalCenter="-50"/>
<s:Button label="Unsubscribe" click="consumer1.unsubscribe()" enabled="{consumer1.subscribed}" verticalCenter="30" horizontalCenter="50"/>
</s:Group>

</s:HGroup>

</s:Application>

其中关键代码是:

view plain

<fx:Declarations>
<s:ChannelSet id="cs">
<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>
<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>
<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>
</s:ChannelSet>

<mx:Consumer id="consumer" destination="simple-feed" channelSet="{cs}"
message="messageHandler(event.message)"/>
<mx:Consumer id="consumer1" destination="testJob-feed" channelSet="{cs}"
message="messageHandler1(event.message)"/>
</fx:Declarations>

注意:

<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>

<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>

<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>

这三个通道的设置中用到的

Aerie是代表context名字。

messagebroker 是代码 web.xml中的配置的MessagebrokerServlet中的url-pattern

amfpolling 等是指 在services-config.xml文件中设置的 channel-definition 下的endpoint 名字
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐