The "Spring ActionScript" Framework – Part 2: Autowiring

In the first part of this series, we looked at how the “Spring ActionScript” framework can help you externalize the configuration and the wiring of your components, and how you can easily obtain configured objects using applicationContext.getObject().

In this second part, we will discuss how you can make these objects available to the views of your application without tightly coupling these views to the framework, and without passing references around through potentially many levels of view containment.

We will build the “Spring ActionScript” version of the InSync contact management application I often use in this blog to explore new technologies. The application has two views: MainView and ContactForm. Both need a reference to a contact RemoteObject to work.

NOTE: This example is intentionally kept simple. In a more partitioned application, you may want to pass a more abstract controller around as opposed to a specific RemoteObject. We will use this approach in part 3.

The views could use applicationContext.getObject() to access their dependencies (in this case the contact RemoteObject), but this approach has a number of problems:

  1. With a dependency on applicationContext, the views would be tightly coupled to the framework.
  2. We would still need to pass a reference to the applicationContext object to the views. This is often solved using the singleton approach which has its own set of problems.

So, instead of the views instantiating or looking up their dependencies, a better approach would be to “inject” these dependencies into the views.

Unlike Swiz, “Spring ActionScript” doesn’t currently have built-in support for an [Autowire] annotation, but Christophe Herreman seems to imply that this feature is coming, and in the meantime, he provides some sample code to support “Spring ActionScript”-powered autowiring in your application. Using this custom code, the inSync application looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	applicationComplete="applicationCompleteHandler()">

	<mx:Script>
	<![CDATA[

	import insync.views.MainView;
	import mx.utils.DescribeTypeCacheRecord;
	import mx.utils.DescribeTypeCache;
	import as3reflect.ClassUtils;
	import org.springextensions.actionscript.context.support.FlexXMLApplicationContext;

	private var applicationContext:FlexXMLApplicationContext;

	private function applicationCompleteHandler():void
	{
		applicationContext = new FlexXMLApplicationContext("applicationContext.xml");
		applicationContext.addEventListener(Event.COMPLETE, applicationContextComplete);
		applicationContext.load();
	}

	private function applicationContextComplete(event:Event):void
	{
		systemManager.addEventListener(Event.ADDED, addedEventHandler);
		var mainView:MainView = new MainView();
		addChild(mainView);
	}

	private function addedEventHandler(event:Event):void
	{
		var autowiredObject:Object = event.target;
		trace("Added to display list: " + autowiredObject);
		var typeInfo:DescribeTypeCacheRecord = DescribeTypeCache.describeType(autowiredObject);
		for each (var metaDataNode:XML in typeInfo.typeDescription..metadata)
		{
			if (metaDataNode.attribute("name") == "Autowired")
			{
				var propertyNode:XML = metaDataNode.parent();
				var property:String = propertyNode.@name.toString();
				trace("Found Autowired property: " + property);
				var objectName:String = property;
				var autowireByType:Boolean = true;

				for each (var arg:XML in metaDataNode.arg)
				{
					if (arg.attribute("value") == "byName")
					{
						autowireByType = false;
					}
				}

				if (autowireByType)
				{
					var clazz:Class = ClassUtils.forName(propertyNode.@type.toString());
					var objectNames:Array = applicationContext.getObjectNamesForType(clazz);
					if (objectNames.length == 1)
					{
						objectName = objectNames[0];
					}
				}
				trace("Autowiring: " + property + " in " + autowiredObject);
				autowiredObject[property] = applicationContext.getObject(objectName);
			}
		}
	}

	]]>
	</mx:Script>

	<mx:Style source="styles.css"/>

</mx:Application>

To be able to inject properties annotated with Autowired, we register as a listener for the ADDED event on systemManager, and introspect each object added to the display list. If the object has [Autowired] properties, those properties are injected (by name or by type) using applicationContext.getObject(objectName). This is also the approach taken by Swiz.

Timing

Before you inject objects into views, you need to make sure the applicationContext.xml file has been loaded and that the objects it defines have been instantiated. To that effect, the applicationContext dispatches an Event.COMPLETE event when it is ready. To make sure all the views of my application can be properly injected (if needed), the strategy I use in this application is to start instantiating the main view only after this event has been triggered. See addChild(mainView) in the applicationContextComplete handler.

The Views

With that infrastructure in place, the two views of the InSync application are easy to write. Their basic setup looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">

	<mx:Script>
		<![CDATA[

			import mx.rpc.remoting.mxml.RemoteObject;

			[Autowired]
			public var contactRemoteObject:RemoteObject;

		]]>
	</mx:Script>

</mx:Canvas>

Installation instructions

NOTE: If you already installed the Swiz version of inSync, you can skip steps 1, 3, 4, 5 and 6.

  1. Install the BlazeDS turnkey server. (To be clear: you don’t have to use BlazeDS to use Spring ActionScript… That’s just what this sample is using.)
  2. Download insyncspringas.zip, and unzip it on your local file system.
  3. Copy insyncspringas/java/classes/insync to blazeds/tomcat/webapps/samples/WEB-INF/classes/insync.
  4. Add the following destination to blazeds/tomcat/webapps/samples/WEB-INF/flex/remoting-config.xml:
  5. <destination id="contacts">
            <properties>
                <source>insync.dao.ContactDAO</source>
                <scope>application</scope>
            </properties>
    </destination>
    

  6. Copy insyncspringas/sampledb/insync to blazeds/sampledb/insync
  7. Edit server.properties in blazeds/sampledb, and modify the file as follows to add the insync database to the startup procedure.

    server.database.0=file:flexdemodb/flexdemodb
    server.dbname.0=flexdemodb
    server.database.1=file:insync/insync
    server.dbname.1=insync
    server.port=9002
    server.silent=true
    server.trace=false
    

  8. Start the database (startdb.bat or startdb.sh)
  9. Start BlazeDS
  10. In Flex Builder, create a new Flex project called insyncspringas. You don’t have to select any “Application server type”.
  11. Copy spring-actionscript.swc and as3reflect.swc from insyncspringas/flex/lib to the lib directory of your project
  12. Copy the files and folders from insyncspringas/flex/src to the src directory of your project
  13. Open applicationContext.xml and make sure the remoteObject endpoint value matches your server setup.
  14. Run the application

Note on Autowiring and Performance

Annotation-based dependency injection is elegant and easy to work with. However, the current implementation that requires a describeType on every object added to the display list has a performance impact. This is maybe something that the Flex framework could help with in the future. For example, we could inject code at compile time to dispatch an AutowireEvent for each Autowired property when a class is instantiated. We would leave it up to the frameworks to provide a specific injection implementation. That would give these frameworks a better event to listen to, and they wouldn’t have to introspect all the objects added to the display list. An alternative would be to have a compiler hook to allow annotation-based code injection at compile time.

In the meantime, you’ll have to identify if the performance impact of the current approach is acceptable in the context of your application. If not, there are ways to improve the basic approach described above:

  • Using Swiz, Aral Balkan uses an autowire property on the views that require autowiring. In the autowiring code, he then uses the hasOwnPropety(“autowiring”) function to identify if the object needs to be autowired before using describeType. This approach still requires some level of introspection on each object added to the display list.
  • Swiz now makes sure it doesn’t perform describeType on classes in the mx packages. This approach could also be added to the code above.
  • Another approach would be for you to programmatically dispatch an AutowireEvent in the initialize event of the views that need to be autowired. This approach is maybe less elegant than a simple annotation, but wouldn’t have the performance impact of introspecting all the objects added to the display list. It would also work for any object in your application, not only the views.

18 Responses to The "Spring ActionScript" Framework – Part 2: Autowiring

  1. Jethro March 12, 2009 at 9:17 am #

    Great post. I particularly liked the fact you also pointed out the performance implication.
    I was looking into using the Autowire approach only yesterday and opted against it based on the performance hit.
    We really need a way to add code at compile time via metadata, but another approach is to make use of the new -define argument to the compiler.

  2. James Ward March 12, 2009 at 10:23 am #

    Alternatively to deal with the performance problems the Flash Player VM could add a Dynamic Proxy:
    http://bugs.adobe.com/jira/browse/ASC-3136

    I believe that is how most Java DI frameworks do the injection.

    Until that happens another potential alternative is to monkey patch what is behind the Managed metadata tag and give it a custom implementation.

    -James

  3. shaun March 12, 2009 at 11:05 am #

    Awesome! I wish you’d posted that a month ago when I was trying to do a very similar thing with Spring Actionscript.. I gave up and used SmartyPants-IOC instead: found it much easier to understand and use (not coming from a Java background). Nevertheless, very glad to find this post – perhaps I’ll give Spring Actionscript another bash :)

  4. cease March 12, 2009 at 6:51 pm #

    Can you post on how sping/blazeds integration works with spring actionscript. Seems similar to me except this autowiring part

  5. magomarcelo March 12, 2009 at 6:52 pm #

    Great explanation, so the current best approach in terms of performance with Spring AS would be using the AutowireEvent? Could it be possible to have an extended example of this?

  6. Mike March 16, 2009 at 1:20 pm #

    “Another approach would be for you to programmatically dispatch an AutowireEvent in the initialize event of the views that need to be autowired. This approach is maybe less elegant than a simple annotation, but wouldn’t have the performance impact of introspecting all the objects added to the display list. It would also work for any object in your application, not only the views.”

    This is the approach the Flicc framework, http://flicc.sourceforge.net, takes with the provided “Configure” tag. This approach also works well with modules – allowing loaded modules to either use thier own IOC config, or be configured by the parent application. A new version of Flicc is to be released in the coming weeks that will provide more documentation on how this benefits modular applications.

  7. Jason Chen March 17, 2009 at 11:01 am #

    I just checked the Flicc framework, I think the idea is good and as I remember, I did read a comment from Christophe Herreman before about providing an injection via MXML instead of the XML itself as an alternative.

    I really think the developers of Flicc can just work with the Spring ActionScript developers and then merge them into one so we will be able to use the DI either way. I still need to really try it out myself more to find out how different it is from the Java version of Spring Framework. I think these are all very good start, all the AC IOC framework developers should just work together to make one, instead of many of them since most of them are doing the similar thing. Then we can have a true Spring in AC.

  8. arnoud May 8, 2009 at 9:29 am #

    Hi Christophe,

    What we really need is a compile option that associates a class with a metatag.

    for example in pseudo::
    mxmlc main.xml -meta [Autowire] nl.artim.Autowire

    then the class would be associated with each variable that has the tag. In your class Autowire you would have a standard interface like handleMetaData(object:*) in which you could do anything with the variable you want.

    for example wiring up a model with the variable ;)

    now the gui would have just the metatag and the way you compile your application determines the behaviour of the metadata tag.

    If you use the the gui in another project you could use another framework and still be able to use the [autowire]. Just hook up another class to the metatag as a compiler option.

    this kind of behavour is really needed and doen’t seem to complicated to build in for the flex compiler team.

    what do you think?

    If you like the idea please tell the flex team as i think you are pretty infulential voice for adobe….

    thanx for the nice blog and extemely good examples!

    Arnoud

  9. arnoud May 8, 2009 at 9:31 am #

    oops sorry about the typos

  10. Vijay November 8, 2009 at 12:36 pm #

    I tried running the app, I was unable to run it successfully.
    Couple of questions.

    Dont we need to give entry for applicationContext.xml in web.xml for it to be available in application context.

    While reading the child component, the code for auto wiring was not able to find and register the [Autowire] component

    Kindly advice.

  11. Vijay November 8, 2009 at 1:20 pm #

    Why I said about the entry in web.xml is because the code is unable to read applicationContext.xml.
    I debugged for numObjectDefinitions and it is ’0′

    What would be the problem, kindly advice

  12. Douglas McCarroll October 22, 2012 at 7:24 pm #

    Hi Christophe,

    The “insyncspringas.zip” link is broken. Any chance of a fix?

    Douglas

Trackbacks/Pingbacks

  1. AS3 Dependency Injection and [Autowire] « shaun smith - March 13, 2009

    [...] Anyhoo.. check this out if you are interested in Spring ActionScript and Autowiring: link [...]

  2. Christophe Coenraets » Blog Archive » The Spring ActionScript Framework — Part 3: Injecting Services (and Mock Services) - March 23, 2009

    [...] we saw how Flex AS allows you to externalize the configuration and the wiring of objects. In part 2, we discussed how you can “autowire” view properties. We intentionally kept the example [...]

  3. OCTO talks ! » Quand Spring s’invite dans une application Flex … - April 23, 2009

    [...] automatiquement les attributs d’une classe alors que Actionscript les supporte. Un début de solution existe mais n’est pas encore inclu dans [...]

  4. Spring ActionScript - Dependency Injection and more for Flex/AIR at Springsteam - Next Generation Java Development | Spring . Flex/AIR . 3D - April 27, 2009

    [...] also a Spring sub forum. Christophe Coenraets also offers articles about it in his blog (2). There are some infos about Maven 2 support. The latest news will be found in the future at [...]

  5. links for 2009-05-12 | diamondTearz - May 12, 2009

    [...] Christophe Coenraets » Blog Archive » The “Spring ActionScript” Framework – Part 2: Autowiri… (tags: actionscript flex framework springactionscript springas3 autowiring) [...]

  6. Building a Flex Application with the Parsley Framework - October 10, 2009

    [...] my recent explorations of “Swiz”, and “Spring ActionScript” (1,2,3), I decided to take the new version of the Parsley framework for a test drive, and build the [...]

Leave a Reply

css.php