In my last entry, I showed how to get a Flex application up and running using the Swiz framework. In this post, I'm going to take a look at what is probably Swiz's killer feature: dependency injection.

Folks familiar with Spring or ColdSpring will recognize the term, but in case you don't, let me quote from Wikipedia:

Conventionally, if an object needs to gain access to a particular service, the object takes responsibility to get hold of that service: either it holds a direct reference to the location of that service, or it goes to a known service locator and requests that it be passed back a reference to an implementation of a specified type of service. By contrast, using dependency injection, the object simply provides a property that can hold a reference to that type of service; and when the object is created a reference to an implementation of that type of service will automatically be injected into that property by an external mechanism.

If that's a little too technical for anyone, I'll translate a bit. The idea is to use some external process to look at the dependencies between your objects, create them in the proper order, and then supply the necessary objects to each other.

Consider how you might be creating objects right now. You could be doing something like this in your Main.mxml file or some kind of configuration object:

var xmlUtils = new XMLUtils();
var contentDelegate = new ContentDelegate();
contentDelegate.xmlUtils = xmlUtils;
var securityController = new SecurityController();
securityController.xmlUtils = xmlUtils;
var contentController = new ContentController();
contentController.securityController = securityController;
contentController.contentDelegate = contentDelegate;
		

So ContentController needs instances of SecurityController and ContentDelegate, which in turn both need an instance of XMLUtils. Kind of nasty, and we're only dealing with four objects. Now think about what that would look like for 40 objects. Or 400. Yikes.

Wouldn't something like this be nicer? Imagine this within the ContentController:

[Autowire]
public var securityController : SecurityController;

[Autowire]
public var contentDelegate : ContentDelegate;
		

This is exactly what Swiz will do. Once you initialize the framework and supply a set of bean definitions (which I did in my last blog entry), Swiz will automatically create those components and resolve all of their dependencies. Which, if you think about it, is pretty killer. But it doesn't stop there. In addition to autowiring Singleton components like controllers and delegates, it will also autowire your views! Yes, it's true. If you have a view containing properties with [Autowire] metadata, Swiz will inject the proper beans into your view as soon as it is added to the stage. Which sweeps away all sorts of issues (or at least issues that I had run into before) related to the creation order of display objects.

A few additional notes about autowiring. In the examples above, I'm using what is called "autowire by type". This means that Swiz looks at the property's type and then looks for a bean that it is managing with the same type. It even works with interfaces and supertypes, which is very useful. Autowire by type is fine for most situations, but if you can't rely on the type alone (such as having Swiz manage multiple different beans of the same type), you can also specify the bean ID if you need to:

[Autowire( bean="userController" )]
public var userController : UserController;
		

Another handy feature is that you can autowire properties that are declared using implicit setters as well. This means that you can execute additional logic when the bean is autowired:

[Autowire]
public function set userController( userController : UserController ) : void
{
	_userController = userController;
	// Run some additional code after the userController is set.
}
public function get userController() : UserController
{
	return _userController;
}
private var _userController : UserController;
		

There are a few other cool features related to autowiring and the process Swiz goes through to resolve the dependencies and create the beans, but I don't want to veer too far off into the low level details. Let's return to the little user manager application that I prototyped in the previous entry. With these ideas about autowiring in mind, lets see how we can apply them to this application. I don't have much in the way of dependencies because there are only a small number of classes, but my Beans.mxml file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<BeanLoader 
	xmlns="org.swizframework.util.*" 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:controller="com.briankotek.swizdemo.controller.*"
	xmlns:business="com.briankotek.swizdemo.delegate.*"
	>

	<controller:UserController id="userController" />
	<business:MockUserDelegate id="userDelegate" />

</BeanLoader>
		

So Swiz is managing two beans for me, a User controller and a User delegate. I want the delegate wired into the controller, so my controller will start off like:

package com.briankotek.swizdemo.controller
{
	import com.briankotek.swizdemo.delegate.IUserDelegate;
	import org.swizframework.controller.AbstractController;

	public class UserController extends AbstractController
	{
	// PUBLIC PROPERTIES
	
	[Autowire]
	public var delegate : IUserDelegate;
	}
}
		

I'm specifying the delegate's type as an interface (IUserDelegate) so that I can swap implementations of the delegate if I want to, such as swapping the MockUserDelegate for a real UserDelegate later on. As long as they both implement the IUserDelegate interface, nothing outside of Swiz needs to know which one is actually being used. We'll look at this delegate in detail in an upcoming post.

For now, let's just see this work. My Main.mxml file to test that the autowiring is working is:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
	xmlns:mx="http://www.adobe.com/2006/mxml" 
	layout="absolute"
	preinitialize="preinitializeHandler( event )"
	>
	
	<mx:Script>
	<![CDATA[
	import com.briankotek.swizdemo.config.Beans;
	import com.briankotek.swizdemo.controller.UserController;
	import org.swizframework.Swiz;
	
	[Autowire]
	[Bindable]
	public var cont : UserController;

	private function preinitializeHandler( event : Event ) : void
	{
	Swiz.loadBeans( [Beans] );
	}
	
	]]>
	</mx:Script>
	
	<mx:Text id="testing" text="Is the UserController set, and was the deleage wired into it? {cont.delegate != null}" />
	
</mx:Application>
		

Which reveals that the controller was indeed wired into my view correctly, as well as confirming that the delegate was wired into the controller correctly. And this was all done in an impressively small amount of code. Hopefully this gets your mind turning about the potential of dependency injection. Remember that this is a deliberately small example, but you can probably see how much of a benefit this would be in larger applications.

That's all for today, but in the next entry, we'll move away from just running a simple test in the Main.mxml. On the whole, Flex apps don't really work like this. Flex is an event-driven framework, with code dispatching events to trigger the execution of additional logic. We'll see how Swiz facilitates this through it's central event dispatcher.

Comments Comments (6) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7869 Views

Comments

  • # Posted By Stephen Judd | 1/14/09 3:05 PM

    Brian, thanks for this series. I'm trying to follow along and construct as I go. Could you tell me more about the files you're creating and how you're organizing, or perhaps post the apps with view source on? I got through the first post, but have questions about which files I need to create to get this example running.

    Thanks, Steve

  • # Posted By Brian Kotek | 1/14/09 5:58 PM

    Hi Stephen. I'm planning to put up the entire application once it's done and I've gone through the elements of it in this series of posts. I'm leery of putting it up as it is, because it contains code that I haven't discussed yet and I'm worried that would cause more confusion than benefit.

    Regarding getting this one example running, all you really need is the Main.mxml, the Beans.mxml, and the two classes UserController and MockUserDelegate. That should work if you modify the UserController in the above code block and change the delegate's type to MockUserDelegate, since you don't have the IUserDelegate interface yet. Or, since the delegate isn't actually doing anything yet and is just an empty class, you can create an empty IUserDelegate interface and have the MockUserDelegate implement it.

    Hopefully that makes sense. I probably caused a bit of confusion by using the interface in the example. My intent was just to show that autowire by type will resolve interfaces in addition to normal class types, but that may have been an unhelpful complication.

    Let me know if that works for you or if you need more information. Thanks!

  • # Posted By Stephen Judd | 1/15/09 6:33 AM

    Thanks Brian, I got it working. I appreciate your assistance and am thoroughly enjoying and benefiting from this series of posts!

  • # Posted By Dennis | 1/16/09 12:28 PM

    Hello Brian,

    I was thinking of putting up a tutorial like this myself. You're doing very well so far!
    Looking forward to see it shape up.

    Cheers!

  • # Posted By kanthonym | 2/11/10 4:29 PM

    Hi Brian, similar to Mr. Judd, i am buidling as I go through the examples. I am not able to get eth expecetd result as i get a waring message in the IDE about the bindinge for delegate.

    I did follow your instruction andboth implement the IUserDelegate as well as the change on the delegate type tro MockUserDelegate.

    However, still no joy

  • # Posted By Brian Kotek | 2/23/10 10:41 AM

    Hmm, without more info I'm not sure what to suggest. You might try posting to the Swiz mailing list at http://groups.google.com/group/swiz-framework since there a many people on that list and you'll probably get more help (from myself included). Thanks.