存档

文章标签 ‘Spring’

发布as-spring 2.4

2010年8月4日 ColorHook 没有评论

ActionScript作为一个编译型(解释+编译)语言,经常需要把一些变量存在外部文件中,如XML文档。但是经常去解析XML文件就不是一件令人愉快的事情,而且变化点不是String, Number等基本类型的话,解析完XML后还要做更多的事情,于是as-spring诞生了。

as-spring是我的一个基于Flash平台的类库,作为一个Ioc反射框架,它在平时工作中给我带来了很多便利。我以前有过几篇博客提到过它:

  1. 在ActionScript中使用简单的Spring框架来实现IOC
  2. 使用Spring来配置RemoteObject
  3. 发布as-spring 2.1

这次升级加入了部分新的特征,用来消除使用过程中遇到的一些不便之处。具体特征如下:

1. 简化基本类型的数据类型定义

以前定义一个Bean都是用<bean>标签来定义,如果我要定义一个String类型的Bean,需要这样来定义:

<bean class='String'>
    <constructor-arg value='This is a String'/>
</bean>

现在可以用<element>标签来定义:

<element value='This is a String' type='String'/>

2. 增加了数组定义

以前定义数组没有好的方法,特别是当数组的元素不是基本类型时。现在可以用<list>标签来定义:

<list id='arr'>
    <element value='true'/>
    <bean>
    </bean>
    <list>
    </list>
</list>
3. 增加了Hash Object的定义

这个功能其实在以前就可以很方便的实现,只是现在加入了一个更符合思维的定义方式:

<map>
    <key name='apple' value='[iPhone,iPad]'>
    <key name='google'>
        <value>android</value>
    </key>
    <key name='ms'>
        <list>
               <element value='XP'/>
               <element value='Vista'/>
               <element value='Win7'/>
        </list>
    </key>
</map>

本来打算加入对flash.utils.Dictionary的定义的,最后还是放弃了,主要是因为暂时没有遇到迫切需要Dictionary的应用场景,如果以后遇到了,可以考虑加入这个功能。

使用Merapi来在AIR和Java中通信

2010年2月2日 ColorHook 没有评论

Merapi是一个用于Java和AIR之间通信的桥接库。通过它可以极大的扩展AIR在本地的执行能力,当然前提是客户端不仅装有AIR运行时虚拟机,还需要安装有Java虚拟机。Merapi通过Socket来通信,使用Adobe的AMF作为数据传输格式。下面看看如何在Flash Builder中创建一个基于Adobe AIR的桌面软件。

在Java和ActionScript两端都存在一名为Bridge的类,它是一个Singleton,用来注册消息类型和发送消息。在这个例子中,AIR向Java端发送一个名为”flashEvent”的消息,消息内容是一个Dictionary实例;并且监听名为”javaEvent”的消息。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="absolute" creationComplete="initApp()">
	<mx:Script>
	<![CDATA[
	import demo.JavaMessageHandler;
	import demo.SerializeMessageHandler;
	import merapi.Bridge;
	import merapi.messages.Message;
	import merapi.error.MerapiErrorMessage;
 
	private function initApp():void{
		//register a error handler
		new SerializeMessageHandler();
		//send a message
		var message:Message=new Message();
		message.type="flashEvent";
		var data:Dictionary=new Dictionary();
		data["name"]="colorhook";
		message.data=data;
		message.send();
		//register a message handler
		Bridge.getInstance().registerMessageHandler("javaEvent",
					new JavaMessageHandler());
	}
	]]>
	</mx:Script>
</mx:WindowedApplication>

CoreErrorHandler继承自EventDispatcher,实现了IMessageHandler接口,它在构造函数中就集成了错误处理。所以不需要显示的在Bridge中注册,而是构造一个实例就行了。SerializeMessageHandler继承自CoreErrorHandler,用来处理全局错误。

package demo{
 
	import merapi.handlers.mxml.CoreErrorHandler;	
	import mx.rpc.events.ResultEvent;
 
	public class SerializeMessageHandler extends CoreErrorHandler{
 
		public function SerializeMessageHandler(type:String=null){
			super(type);
			this.addEventListener(ResultEvent.RESULT,onMessageResult);
		}
 
		private function onMessageResult(event:ResultEvent):void{
			trace("SerializeMessageHandler:",event);
		}
	}
}

JavaMessageHandler实现了接口IMessageHandler,并在handleMessage方法中输出从Java中返回的数据。

package demo{
 
	import merapi.handlers.IMessageHandler;
	import merapi.messages.IMessage;
 
	public class JavaMessageHandler implements IMessageHandler{
 
		public function handleMessage(message:IMessage):void{
			trace(message.type);
			trace(message.data);
		}
	}
}

编译运行会发现控制台输出SerializeMessageHandler中的trace信息,因为目前还没有开启Java端的ServerSocket。所以下面来启动一个Java程序。首先调用Bridge.open()来启动ServerSocket。然后监听名为”flashEvent”的消息。

package demo;
 
import org.apache.log4j.Logger;
import merapi.Bridge;
 
public class Application {
 
	protected Logger logger=Logger.getLogger(Application.class);
 
	public Application(){
		logger.info("Application start");
		//open Bridge
		Bridge.open();
		//register a message handler
		Bridge.getInstance().registerMessageHandler("flashEvent",
			new AIRMessageHandler());
	}
 
	public static void main(String[] args){
		new Application();
	}
}

在消息处理器AIRMessageHandler中,输出来自Flash的数据,AMF将ActionScript中的Dictionary映射为Java中的Map。接受到数据之后,我们再从Java中发出一个Message,该Message携带了一个List类型的数据,在Flash中,它会被映射成Array类型。

package demo;
 
import java.util.*;
import org.apache.log4j.Logger;
import merapi.handlers.IMessageHandler;
import merapi.messages.IMessage;
import merapi.messages.Message;
 
public class AIRMessageHandler implements IMessageHandler {
 
	protected Logger logger=Logger.getLogger(AIRMessageHandler.class);
 
	@Override
	public void handleMessage(IMessage message) {
		//handle message
		logger.info(message.getType());
		Map<String,String> map=(Map<String, String>)message.getData();
		logger.info(map.get("name"));
		//send a new message
		Message newMessage=new Message();
		newMessage.setType("javaEvent");
		List<String> list=new ArrayList<String>();
		list.add("Flash Player");
		list.add("AIR");
		newMessage.setData(list);
		newMessage.send();
	}
}

Merapi在Java端用到了Spring, log4j和Adobe AMF相关包, 所以运行时要保证项目包含了这些jar包。可以从MerapiGoogle Code中得到这些包。

AIR2的发布,让我们在AIR和Java通信方面有了新的选择: flerry
flerry使用了AIR2的新特性NativeProcess,它直接创建了一个进程了执行Java程序。从其作者的blog上可以了解更多信息: http://www.riaspace.net/2010/01/flerry-flex-java-bridge-for-adobe-air-2-0/

发布as-spring 2.1

2009年8月10日 ColorHook 2 条评论

此版本已更新,具体请看:发布as-spring 2.4


由于Christophe Herreman 的actionscript-spring框架已经十分的成熟和完善,而自己也有个简单的库叫actionscript-spring,于是更名为as-spring以示区别,现在升级到2.1版本,相对于2.0增加的功能有:

1.支持import多配置文件。

<import resource="spring-config2.xml"/>
<import resource="spring-config3.xml"/>

2.支持属性内联Bean。

<bean id="dp" class="Object">
    <property name="prop">
        <bean class="Object">
        </bean>
    </property>
</bean>

3.支持参数内联Bean。

<bean id="source" class="Array">
    <constructor-arg>
        <bean class="flash.display.Sprite"/>
    </constructor-arg>
    <constructor-arg>
        <bean class="flash.media.Sound"/>
    </constructor-arg>
</bean>
<bean id="loader" class="flash.net.URLLoader">
    <method name="load">
        <method-arg>
            <bean class="flash.net.URLRequest">
                <property name="url" value="http://www.colorhook.com"/>
            </bean>
        </method-arg>
    </method>
</bean>

使用Spring来配置RemoteObject

2009年4月9日 ColorHook 没有评论

在Flex中使用RemoteObject可以很容易地对Java对象进行RPC调用,但是其配置较为复杂。使用AMFPHP对PHP进行RPC调用只需要指定RemoteObject的destination和endpoint属性即可,而在BlazeDS环境下,需要创建ChannelSet和Channel对象。

通常的做法是使用一个xml文件来配置一个Java destination,Flex在编译的时候会根据配置信息来创建一个完整的RemoteObject对象。但是如果需要更改该RemoteObject对象的destination或者ChannelSet等属性,则需要重新编译,这样的话很是麻烦。

Spring的IOC容器可以很好解决这个问题,它把对象的创建方式声明在外部,然后由容器来动态生成。

使用我的Spring框架来实现这个想法。

1.创建远程的Java对象,编译成class文件放在文件夹WEB-INF\classes\demo下面。

package demo;
public class HelloBlazeDS{
 
	public HelloBlazeDS(){
	}
 
	public String sayHello(String info){
		return "[BlazeDS return] : "+info;
	}
}

2.配置BalzeDS。
打开文件WEB-INF\flex\remoting-config.xml,向其中添加一个destination定义。

<destination id="HelloBlazeDS">
	<properties>
		<source>demo.HelloBlazeDS</source>
	</properties>
</destination>

3.创建Spring的配置文件spring_config.xml。

<?xml version="1.0" encoding="utf-8"?>
<spring-config>
	<beans>
		<bean id="remoteBean" class="mx.rpc.remoting.mxml.RemoteObject">
			<property name="destination" value="HelloBlazeDS"/>
			<property name="channelSet" ref="channelSet"/>
		</bean>
 
		<bean id="channelSet" class="mx.messaging.ChannelSet">
			<method name="addChannel">
				<method-arg ref="channel"/>
			</method>
		</bean>
 
		<bean id="channel" class="mx.messaging.channels.AMFChannel">
			<property name="id" value="my-amf"/>
			<property name="uri" value="http://localhost:8080/blazeds/messagebroker/amf"/>
		</bean>
	</beans>
</spring-config>

该配置文件声明了一个Bean名字叫remoteBean,它是一个RemoteObject对象,这个Bean还引用了channelSet和channel这两个Bean。

4.在Flex中使用Spring,下面是代码片段。

//导入加载配置文件的类ContextLoader
import com.colorhook.spring.context.ContextLoader;
 
private var contextLoader:ContextLoader;
private var remoteService:RemoteObject;
 
//初始化时加载配置文件
private function init():void{
	contextLoader=new ContextLoader();
	contextLoader.addEventListener("complete",onContextLoaderComplete);
}
 
//加载完成之后创建RemoteObject,并调用远程方法sayHello
private function onContextLoaderComplete(event:Event):void{
	contextLoader.removeEventListener("complete",onContextLoaderComplete);
	remoteService=contextLoader.contextInfo.getBean("remoteBean");
	remoteService.sayHello.addEventListener(ResultEvent.RESULT,onSayHelloResult);
	remoteService.sayHello("Spring and BlazeDS");
}
//输出返回结果
private function onSayHelloResult(event:ResultEvent):void{
	Alert.show(String(event.result));
}
分类: Develop & Design 标签: , , , ,

强大的Spring ActionScript框架

2009年3月26日 ColorHook 没有评论

比利时的Christophe HerremanSpring ActionScript框架(以前的pranaframework)的创始人和主要开发成员之一,Spring ActionScript的当前版本是0.7。

当前版本的Spring ActionScript已经实现了IOC,反射编程框架,集成了Cairngorm和PureMVC框架。接下来会开发一个MVCS( Model-View-Controller-Service)的架构,并且加入AOP(Aspect Oriented Programming)面向切面编程。(比我的Spring框架不知道要强多少倍!!)

使用pranaframework框架的一个例子(与使用Spring ActionScript类似,只是包名改了):

1.定义XML配置文件.

prana_config.xml

<?xml version="1.0" encoding="utf-8"?>
<objects>
	<object id="sound" class="flash.media.Sound"/>
	<object id="request" class="flash.net.URLRequest">
		<constructor-arg type="String" value="testSound.mp3"/>
	</object>	
</objects>

2.加载配置文件,生成对象.

ActionScript时间轴代码

import org.pranaframework.context.support.XMLApplicationContext;
 
var context:XMLApplicationContext=new XMLApplicationContext("prana_config.xml");
context.addEventListener("complete",onContextComplete);
context.load();
 
function onContextComplete(e:Event):void{
	var sound=context.getObject("sound")
	sound.load(context.getObject("request"))
	sound.play()
}

在ActionScript中使用简单的Spring框架来实现IOC

2009年3月26日 ColorHook 没有评论

此版本已更新,具体请看:发布as-spring 2.4

Flash跨平台的实现和Java一样,都是通过虚拟机来实现的,Flash Player充当了适配器(Adapter)的作用。swf文件是编译过的二进制文件,类似与Java的class文件。一般来说,如果改变swf文件,需要修改源文件然后重新编译,这样或多或少会带来麻烦。IOC(Inversion Of Control)是用来分离关注的一种模式,大名鼎鼎的Java Spring框架就是以IOC容器来实现DI(Dependency Injection)。Java Spring的IOC容器是XML驱动的,意味着可以修改XML文件来更改程序的行为。把这种方式移植到Flash平台,就成了Flash的Spring了。

1.加载参数

该功能在新版本中被移除了,有新的方式可以替代。


在应用中可能会有随时更改的参数,或者这个参数还没有得到确定。如果把参数写进XML文件中,即使以后参数发生更改,也不需要重新编译程序。
为这个过程建立一个统一的接口,以后的相同的需求就可以重复使用。

这个Spring配置文件定义的7个参数,分别对应基本类型Number,int,uint,String,Boolean,Array,Date

spring_config.xml
<?xml version="1.0" encoding="utf-8"?>
<spring-config>
 
	<params>
		<param name="p_Number"  type="Number" value="3.14159265358979323"/>
		<param name="p_int" type="int"><value>-1</value></param>
		<param name="p_uint"  type="uint" value="1"/>
		<param name="p_String"  type="String" value="string"/>
		<param name="p_Boolean" type="Boolean" value="false"/>
		<param name="p_Array" value="[1,2,3,4,5]"/>
		<param name="p_Date" type="Date" value=""/>
	</params>
 
</spring-config>


SpingLoadParameterExample.as
package{
 
	/**
	 * @author colorhook
	 * @copyright http://www.colorhook.com
	 */
 
	 import com.colorhook.spring.context.ContextLoader;
	 import com.colorhook.spring.context.ContextInfo;
 
	 import flash.display.Sprite;
	 import flash.events.Event;
 
	 public class SpingLoadParameterExample extends Sprite{
 
		 private var contextLoader:ContextLoader;
 
		 public function SpingLoadParameterExample(){
			 contextLoader=new ContextLoader();
			 contextLoader.addEventListener(Event.COMPLETE,onContextLoaderComplete);
			 contextLoader.load("spring_config.xml");
		 }
 
		 private function onContextLoaderComplete(e:Event):void{
			print("p_Number");
			print("p_int");
			print("p_uint");
			print("p_Boolean");
			print("p_String");
			print("p_Array");
			print("p_Date");
		 }
 
		 private function print(name:String):void{
			 var contextInfo:ContextInfo=contextLoader.contextInfo;
			 var param:*=contextInfo.getParameter(name);
			 trace("[Parameter] ",name," : ",param);
		 }
	 }
}

2.从SWF文件中加载Class

通过加载一个SWF文件,可以使用其中包含的类。你可能为了减小单个文件的尺寸把文件分割成一块一块,类定义也是一样的,把一个类库编译成一个swf文件,然后在需要的时候加载它,这有点想RSL,但是与RSL还是有区别的,Flash Player可以缓存RSL,而swf被浏览器缓存。

这个Spring配置文件定义的2个library和2个Class,2个lib中都有名为MyCircle的类,circleInNewDomain会被加载到独立的应用域。

spring_config.xml
<?xml version="1.0" encoding="utf-8"?>
<spring-config>
 
	<libs>
		<lib name="circleInSameDomain" path="CircleInSameDomain.swf"/>
		<lib name="circleInNewDomain" path="CircleInNewDomain.swf" same-domain="false"/>
 
	</libs>
 
	<classes>
		<class name="CircleInNewDomain" class="MyCircle" lib="circleInNewDomain" />
		<class name="CircleInSameDomain" class="MyCircle" lib="circleInSameDomain"  />
	</classes>
 
</spring-config>


SpringLoadClassExample.as
package {
 
	/**
	 * @author colorhook
	 * @copyright http://www.colorhook.com
	 */
 
	import com.colorhook.spring.context.ContextLoader;
	import com.colorhook.spring.context.ContextInfo;
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.MovieClip;
	public class SpringLoadClassExample extends Sprite {
 
		private var contextLoader:ContextLoader;
 
		public function SpringLoadClassExample() {
			contextLoader=new ContextLoader();
			contextLoader.addEventListener(Event.COMPLETE,onContextLoaderComplete);
			contextLoader.load("spring_config.xml");
		}
 
		private var ClassInSameDomain:Class;
		private var ClassInNewDomain:Class;
 
		private function onContextLoaderComplete(e:Event):void {
			var contextInfo:ContextInfo=contextLoader.contextInfo;
			ClassInSameDomain=contextInfo.getClass("CircleInSameDomain");
			ClassInNewDomain=contextInfo.getClass("CircleInNewDomain");
			var instanceInSameDomain:MovieClip=new ClassInSameDomain() as MovieClip;
			var instanceInNewDomain:MovieClip=new ClassInNewDomain() as MovieClip;
			instanceInNewDomain.x=200;
			addChild(instanceInSameDomain);
			addChild(instanceInNewDomain);
			trace("ClassInSameDomain:",ClassInSameDomain);
			trace("ClassInNewDomain:",ClassInNewDomain);
		}
 
	}
}

3.通过反射生成对象

使用XML来定义一个对象,然后在特别的某个时刻来生成他,然后注入到你的应用程序中,这可以降低程序的耦合性,提高软件的可维护性。
通过XML定义,可以创建类的实例,也可以用过工厂方法得到一个对象。

这个Spring配置文件定义的四个Bean。personBean是一个单例,类型是Object。requestBean是最普通的Bean。randomNum是一个工厂Bean,sprite也是普通的Bean,它定义了创建后执行的动作。

spring_config.xml
<?xml version="1.0" encoding="utf-8"?>
<spring-config>
	<beans>
 
		<bean id="personBean" class="Object" singleton="true">
			<property name="name" value="John"/>
			<property name="sex"><value>male</value></property>
		</bean>
 
		<bean id="requestBean" class="flash.net.URLRequest">
			<constructor-arg type="String" value="http://www.colorhook.com"/>
			<property name="method" value="GET"/>
		</bean>
 
		<bean id="randomNum" class="Math" factory-method="random">
		</bean>
 
		<bean id="sprite" class="flash.display.Sprite">
			<property name="graphics">
				<method name="beginFill">
					<method-arg value="0xFF0000"/>
				</method>
				<method name="drawRect">
					<method-arg value="0"/>
					<method-arg value="0"/>
					<method-arg value="100"/>
					<method-arg value="100"/>
				</method>
			</property>
			<property name="x" value="200"/>
			<property name="y" value="100"/>
		</bean>
 
	</beans>
</spring-config>


SpringLoadBeanExample.as
package {
 
	/**
	 * @author colorhook
	 * @copyright http://www.colorhook.com
	 */
 
	import com.colorhook.spring.context.ContextLoader;
	import com.colorhook.spring.context.ContextInfo;
 
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLRequest;
 
	public class SpringLoadBeanExample extends Sprite {
 
		private var contextLoader:ContextLoader;
		private var contextInfo:ContextInfo;
 
		public function SpringLoadBeanExample() {
			contextLoader=new ContextLoader();
			contextLoader.addEventListener(Event.COMPLETE,onContextLoaderComplete);
			contextLoader.load("spring_config.xml");
		}
 
		private function onContextLoaderComplete(e:Event):void {
			contextInfo=contextLoader.contextInfo;
			testRefBean();
			trace("--------------------------------");
			testSingletonBean();
			trace("--------------------------------");
			testFactoryBean();
			trace("--------------------------------");
			testMethodBean();
		}
 
		private function testRefBean():void {
			var requestBean:URLRequest=contextInfo.getBean("requestBean");
			trace(requestBean);
			trace(requestBean.url);
			trace(requestBean.method);
		}
 
		private function testSingletonBean():void {
			var personBean:Object=contextInfo.getBean("personBean");
			printObject(personBean);
			personBean.blog="http://www.colorhook.com/blog";
			personBean=contextInfo.getBean("personBean");
			printObject(personBean);
		}
 
		private function testFactoryBean():void {
			var bean:*=contextInfo.getBean("randomNum");
			trace(bean);
			bean=contextInfo.getBean("randomNum");
			trace(bean);
		}
 
		private function testMethodBean():void{
			var sprite:Sprite=contextInfo.getBean("sprite");
			addChild(sprite)
		}
 
		private function printObject(object:*):void {
			for (var i in object) {
				trace(i," : ",object[i]);
			}
		}
	}
}


可以从下面的地址下载到框架的源文件,示例的源文件和帮助文档。

http://www.colorhook.com/Spring_ActionScript3_V2.zip
源码和文档已托管在google code上:http://code.google.com/p/as-spring