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 名字
配置过程和源码:
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 名字
相关文章推荐
- flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程。
- flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程。
- 使用spring注解 自动装配以及自动扫描机制 实现零xml配置的前提
- 使用spring注解 自动装配以及自动扫描机制 实现零xml配置的前提
- Spring(十一)使用Spring的注解方式实现面向切面技术AOP
- 使用spring注解 自动装配以及自动扫描机制 实现零xml配置的前提
- 利用Spring IOC技术实现用户登录验证机制
- 使用spring注解 自动装配以及自动扫描机制 实现零xml配置的前提
- Spring——使用Spring的注解方式实现面向切面技术AOP
- spring源码剖析(五)利用AOP实现自定义Spring注解
- 合理使用“.NET 扩展方法”来简化代码(例子:空值判断,利用扩展方法实现LINQ操作符ForEach)
- 使用Spring的注解方式实现AOP
- spring3中使用注解方式实现定时器调度任务
- springboot-30-security(三)使用注解实现权限控制
- spring注解 @Scheduled(cron = "0 0 1 * * *")的使用来实现定时的执行任务
- Spring使用AspectJ注解和XML配置实现AOP
- 分布式缓存技术redis学习系列(五)——spring-data-redis与JedisPool的区别、使用ShardedJedisPool与spring集成的实现及一致性哈希分析
- Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录
- 【Spring】使用@Service注解写的一个小例子
- 使用SpringBoot通过自定义注解+AOP+全局异常处理实现参数统一非空校验