Chapter 6. Autowiring

6.1. Autowiring instances

The Spring Actionscript container is able to autowire relationships between collaborating objects. This means that it is possible to automatically let Spring Actionscript resolve collaborators (other objects) for your object by inspecting the contents of the object definition. The autowiring functionality has five modes. Autowiring is specified per object and can thus be enabled for some objects, while other objects will not be autowired. Using autowiring, it is possible to reduce or eliminate the need to specify properties or constructor arguments, thus saving a significant amount of typing. When using XML-based configuration metadata, the autowire mode for a object definition is specified by using the autowire attribute of the <object/> element. The following values are allowed:

Table 6.1. Autowiring modes
Mode Explanation
no No autowiring at all. Object references must be defined via a ref element. This is the default, and changing this is discouraged for larger deployments, since explicitly specifying collaborators gives greater control and clarity. To some extent, it is a form of documentation about the structure of a system.
byName Autowiring by property name. This option will inspect the container and look for an object named exactly the same as the property which needs to be autowired. For example, if you have an object definition which is set to autowire by name, and it contains a master property, Spring Actionscript will look for an object definition named master, and use it to set the property.
byType Allows a property to be autowired if there is exactly one object of the property type in the container. If there is more than one, a fatal exception is thrown, and this indicates that you may not use byType autowiring for that object. If there are no matching objects, nothing happens; the property is not set.
constructor This is analogous to byType, but applies to constructor arguments. If there isn't exactly one object of the constructor argument type in the container, a fatal error is raised.
autodetect Chooses constructor or byType through introspection of the object class. If a default (parameterless) constructor is found, the byType mode will be applied.

Note that explicit dependencies in <property/> and <constructor-arg/> settings always override autowiring. Please also note that it is not currently possible to autowire so-called simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). (This is by-design and should be considered a feature.) When using either the byType or constructor autowiring mode, it is possible to wire arrays. In such cases all autowire candidates within the container that match the expected type will be provided to satisfy the dependency.

It is important to understand the various advantages and disadvantages of autowiring. Some advantages of autowiring include:

  • Autowiring can significantly reduce the volume of configuration required. However, mechanisms such as the use of a object template (discussed elsewhere in this chapter) are also valuable in this regard.

  • Autowiring can cause configuration to keep itself up to date as your objects evolve. For example, if you need to add an additional dependency to a class, that dependency can be satisfied automatically without the need to modify configuration. Thus there may be a strong case for autowiring during development, without ruling out the option of switching to explicit wiring when the code base becomes more stable.

Some disadvantages of autowiring:

  • Autowiring is more magical than explicit wiring. Although, as noted in the above table, Spring Actionscript is careful to avoid guessing in case of ambiguity which might have unexpected results, the relationships between your Spring Actionscript-managed objects are no longer documented explicitly.

  • Wiring information may not be available to tools that may generate documentation from a Spring Actionscript container.

Another issue to consider when autowiring by type is that multiple object definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or maps, this is not necessarily a problem. However for dependencies that expect a single value, this ambiguity will not be arbitrarily resolved. Instead, if no unique object definition is available, an Exception will be thrown. You do have several options when confronted with this scenario. First, you may abandon autowiring in favor of explicit wiring. Second, you may designate that certain object definitions are never to be considered as candidates by setting their 'autowire-candidate' attributes to 'false' as described in the next section. Third, you may designate a single object definition as the primary candidate by setting the 'primary' attribute of its <object/> element to 'true'.

When deciding whether to use autowiring, there is no wrong or right answer in all cases. A degree of consistency across a project is best though; for example, if autowiring is not used in general, it might be confusing to developers to use it just to wire one or two object definitions.

This is an example of autowiring using XML configuration:

<object class="..." autowire="byType"/>

MXML configuration:

<sas:Object clazz="{...}" autoWireMode="byType"/>

Metadata configuration:

[Component(autowire="byType")]

Note

If a property is of type IApplicationContext or ApplicationDomain the application context instance or its ApplicationDomain property will be injected when autowiring byType.

6.1.1. Autowiring objects using annotations

A different way of letting the Spring Actionscript container know how to configure an object is by adding specific metadata annotations to the component's sources. Obviously this is only possible when the developer actually has access to the source code. Thus, this solution does not apply to the situation in which you'd like to autowire existing objects, such as the ones that are already part of the Flex framework.

The simplest way to inject a property by type is by decorating its source like this:

public class ExampleComponent extends UIComponent {

	[Inject]
	public var modelInstance:IModelLocator;

	public function ExampleComponent() {
		super();
	}

}

Once this component is created (or added to the stage), the Spring Actionscript container will search in its container an object of type IModelLocator and assign it to the modelInstance property of the ExampleComponent.Wiring by name is also possible, all that is needed is a little extra metadata:

public class ExampleComponent extends UIComponent {

	[Inject(mode='byName')]
	public var modelInstance:IModelLocator;

	public function ExampleComponent() {
		super();
	}

}

Now the Spring Actionscript container will look for an object in its configuration with the id 'modelInstance' and assign this to the modelInstance property of the ExampleComponent.There's another way of injecting by name, suited for the situation where the name of the property and the id in the configuration don't match. What if the IModelLocator instance described in the configuration has an id called 'modelLocator' and for some reason this can't be easily changed?

Easy, you can define the exact name in the metadata as follows:

public class ExampleComponent extends UIComponent {

	[Inject(name='ModelLocator')]
	public var modelInstance:IModelLocator;

	public function ExampleComponent() {
		super();
	}

}

All these examples use the [Inject] metadata, Spring Actionscript supports this metadata to help in the effort to to standardise AS3 DI Metadata tags.

The original [Autowired] metadata, however, is still supported as well.

Note

When using the [Inject] or [Autowired] metadata do not forget to add these compiler settings to your Flex project: -keep-as3-metadata += Inject,Autowired.

6.1.2. Binding an object property to a property of an object in the container

To keep your objects as decoupled as possible it might be preferred not to inject the modelInstance into it, but just a certain property of the model. Since the data in the model is subject to change (usually it is populated with data retrieved from remote method invocations), it would also be good to bind your view to the model.

This can be achieved by using the following metadata:

public class ExampleProductListComponent extends UIComponent {

	[Autowired(name='ModelLocator',property='products')]
	public var products:ArrayCollection;

	public function ExampleProductListComponent() {
		super();
	}

}

This example assumes that the ModelLocator object has a property called 'products' of type ArrayCollection. A binding is established between these two objects, so when the products ArrayCollection in the model in updated, so will the component.

The property value can also be a chain of objects, so this will work as well:

public class ExampleProductListComponent extends UIComponent {

	[Autowired(name='ModelLocator',property='productManager.products')]
	public var products:ArrayCollection;

	public function ExampleProductListComponent() {
		super();
	}

}

Note

Since this functionality makes use of Flex binding it is therefore only available in Flex applications.

6.1.3. Injecting an object property with an external property value

Its also possible to inject the value of an external property into a autowired object. (If you want to know more about external properties read the section 'Using property files').

To do this add metadata to your source like this:

public class ExampleComponent extends UIComponent {

	[Autowired(externalProperty='currentURL')]
	public var websiteURL:String;

	public function ExampleComponent() {
		super();
	}

}

Where the value of the externalProperty metadata argument key matches the key in one of the loaded property files.

6.1.4. Autowiring stage components

Spring Actionscript knows one situation when used in conjunction with the Flash which differs from other Spring implementations. This is when visual components (often declared as MXML components) need to be autowired. In this case the container can't be responsible for the actual creation of the components, so it is deferred back to the Flex/Flash application.

Concretely, we want to retain the expressiveness of MXML declaration and combine it with the IoC capabilities of Spring Actionscript.

For example, given this (very simple) piece of MXML markup:

<?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:custom="http://www.mydomain.com/flexcomponents">

	<custom:OrderView myDependency="{this.applicationModel}" id="exampleComponent"/>

</s:Application>

In this case the application model instance is directly injected through concrete markup. In a lot of cases this is perfectly acceptable, but Spring Actionscript offers a little extra flexibility by being able to inject the model instance at runtime.

Just like a regular object, the OrderView component may be annotated with [Inject] or [Autowired] metadata.

Spring Actionscript is able to perform these dependency injections by hooking an event listener into the Event.ADDED_TO_STAGE event and process the components right after they have been added to the stage.

Note

The engine that is responsible for managing the stage processing in the FlashStageObjectProcessorRegistry that is offered by the AS3Commons-stageprocessing library.

To make use of the metadata processor that handles all of the functionality described in the following sections add this to the XML configuration:

<object id="autowiringStageProcessor" class="org.springextensions.actionscript.stage.DefaultAutowiringStageProcessor"/>

MXML configuration:

<sas:Object id="autowiringStageProcessor" clazz="{DefaultAutowiringStageProcessor}"/>

Or use this custom component:

<sas:StageAutowireProcessor/>

There are several ways of configuration for this stituation, in the following sections we will look at them one by one.

Note

There are several shortcuts to add these processors to your configuration. How this works and how to build your own extensions is covered in the section 'Extending configurations'.

Note

The autowiring of stage components is part of the Stage extension point. To read more about this and learn how to create your own processors, check out the section 'Stage object processors'.

Note

To enable stage wiring it is important that the application context is associated with one or more root views. These can be passed as a Vector to the constructor or at a later stage by using the addRootView() method.

6.1.4.1. Determining which stage objects will be autowired

By default the DefaultSpringObjectSelector Default <code>IObjectSelector</code> used for Spring Actionscript stage wiring. Deny all flash. mx. spark.and _(skins, etc) classes. is used to filter out which stage components will be autowired. It is adviced though to create your own IObjectSelector implementation to streamline the selection process. (A LOT of components get added and removed from the stage.)

Now, imagine a situation where you know beforehand that only components that implement a specific marker interface need to be autowired. In that case you can implement a much simpler selection process. Let's say the marker interface is called IAutowiredComponent, then the implementation of the IObjectSelector.approve() method needs to be simply this:

public function approve(object:Object):Boolean {
	return (object is IAutowiredComponent);
}

This will certainly boost the efficiency of the selection process!

6.1.4.2. Autowiring stage components using Object Definitions

Stage components can be configured using metadata that describes the desired injections, but this can also be entirely expressed a regular object definitions. Here is how to configure the ExampleComponent to be autowired by type:

<object id="exampleComponent" class="classes.components.ExampleComponent" autowire="byType" singleton="false"/>

In this example we assume that the ExampleComponent instance on the stage has a name property with the value exampleComponent.

Let us be clear immediately though, autowiring a stage component in this way is a bad idea. The Spring Actionscript container will, in this case, actually loop through every property of the ExampleComponent instance and try to find a matching wiring candidate in the container. This will very quickly become very slow, so please regard this example as a proof of concept but don't use it in any actual production code.

Autowiring by name is almost the same and the same warning as for wiring by type is applicable: don't do it.

The most obvious way of configuring the ExampleComponent is by simply injecting the property explicitly like this:

<object id="exampleComponent" class="classes.components.ExampleComponent" scope="stage">
	<property name="modelInstance" ref="modelLocator"/>
</object>

MXML configuration:

<sas:Object id="exampleComponent" clazz="{ExampleComponent}" scope="stage">
	<sas:Property name="modelInstance" ref="{modelLocator}"/>
</object>

Metadata configuration:

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" 
		  xmlns:s="library://ns.adobe.com/flex/spark" 
		  xmlns:mx="library://ns.adobe.com/flex/mx"
		  implements="com.classes.stage.IAutowiredComponent">
	<fx:Metadata>
		[Component(id="exampleComponent",scope="stage")]
	</fx:Metadata>
	<fx:Script>
		<![CDATA[
			[Property(ref="modelLocator")]
			public var modelInstance:ModelLocator;
		]]>
	</fx:Script>
</s:VGroup>

Note

Do take notice of the scope="stage" attribute on each of these configuration examples. Don't forget to add this value to each and every stage component definition entry. Spring Actionscript defaults an object definition to a singleton scope and instantiates every singleton in the configuration at startup. Failing to add the scope="stage" attribute will result in Spring Actionscript creating a whole bunch of stage component instances unnecessarily.

6.1.4.3. How to determine which object definition to use for which stage component

Once a component has been added to the stage and is being processed by the autowiring processor it will need a mechanism that supplies an object definition for the component in question. This particular task is bestowed upon the IObjectDefinitionResolver Objects implementing this interface are used to retrieve an <code>IObjectDefinition</code> for already existing objects to be wired. Useful for <code>IDependencyInjector</code> that have to deal with already existing objects and can't use factory methods. interface. This interface is a small one:

public interface IObjectDefinitionResolver {
	function resolveObjectDefinition(object:*):IObjectDefinition;
}

An object that implements this interface is responsible for retrieving, or creating, an object definition for a given object instance. Spring Actionscript by default offers the DefaultObjectDefinitionResolver Default <code>IObjectDefinitionResolver</code> used for stage wiring, it is able to associate an object definition with a stage component instance. <p> Attempt to resolve an <code>IObjectDefinition</code> for the passed object: <ol> <li>Name lookup. Uses <code>objectIdProperty</code> as the object property name to be used to match an object definition (default: <code>"name"</code>).</li> <li>Type lookup. Used if the preceding hasn't found a matching object definition. Will try to find an object definition with the same type of the object (it will assign the object definition only if a single matching object definition is found).</li> </ol> </p> class. This implementation uses different strategies to retrieve the appropriate IObjectDefinition Describes an object that maintains the configuration for an object's instantiation. for an object. First of all it uses the value of its objectIdProperty property to find the object definition by name. By default the value of this property is 'name. This means that if a stage component is being examined whose name property has a value of 'myStageComponent', the DefaultObjectDefinitionResolver Default <code>IObjectDefinitionResolver</code> used for stage wiring, it is able to associate an object definition with a stage component instance. <p> Attempt to resolve an <code>IObjectDefinition</code> for the passed object: <ol> <li>Name lookup. Uses <code>objectIdProperty</code> as the object property name to be used to match an object definition (default: <code>"name"</code>).</li> <li>Type lookup. Used if the preceding hasn't found a matching object definition. Will try to find an object definition with the same type of the object (it will assign the object definition only if a single matching object definition is found).</li> </ol> </p> will look for an object definition with an id of 'myStageComponent'. If the object definition can't be found it will fall back on trying to find an object definition by type, but only if the lookupByType property on the DefaultObjectDefinitionResolver Default <code>IObjectDefinitionResolver</code> used for stage wiring, it is able to associate an object definition with a stage component instance. <p> Attempt to resolve an <code>IObjectDefinition</code> for the passed object: <ol> <li>Name lookup. Uses <code>objectIdProperty</code> as the object property name to be used to match an object definition (default: <code>"name"</code>).</li> <li>Type lookup. Used if the preceding hasn't found a matching object definition. Will try to find an object definition with the same type of the object (it will assign the object definition only if a single matching object definition is found).</li> </ol> </p> is set to true.

If both of these options fail the DefaultObjectDefinitionResolver Default <code>IObjectDefinitionResolver</code> used for stage wiring, it is able to associate an object definition with a stage component instance. <p> Attempt to resolve an <code>IObjectDefinition</code> for the passed object: <ol> <li>Name lookup. Uses <code>objectIdProperty</code> as the object property name to be used to match an object definition (default: <code>"name"</code>).</li> <li>Type lookup. Used if the preceding hasn't found a matching object definition. Will try to find an object definition with the same type of the object (it will assign the object definition only if a single matching object definition is found).</li> </ol> </p> will return null. This will happen in the case that a stage component has been decorated with autowiring metadata and has no further use for an object definition. Of course, the both can be combined as well, but its open to discussion whether this is advisable. To use the DefaultObjectDefinitionResolver Default <code>IObjectDefinitionResolver</code> used for stage wiring, it is able to associate an object definition with a stage component instance. <p> Attempt to resolve an <code>IObjectDefinition</code> for the passed object: <ol> <li>Name lookup. Uses <code>objectIdProperty</code> as the object property name to be used to match an object definition (default: <code>"name"</code>).</li> <li>Type lookup. Used if the preceding hasn't found a matching object definition. Will try to find an object definition with the same type of the object (it will assign the object definition only if a single matching object definition is found).</li> </ol> </p> add this to your XML configuration:

<object id="defaultObjectDefinitionResolver"
	class="org.springextensions.actionscript.stage.DefaultObjectDefinitionResolver"/>

MXML configuration:

<sas:Object id="defaultObjectDefinitionResolver"
	clazz="{DefaultObjectDefinitionResolver}"/>

By default the DefaultObjectDefinitionResolver uses the name property to match an object definition with a stage component. You can change this by setting the objectIdProperty property on the definition resolver. So, in case you'd like to use the id property for matching, change the configuration to this:

<sas:Object id="defaultObjectDefinitionResolver"
	clazz="{DefaultObjectDefinitionResolver}">
	<sas:Property name="objectIdProperty" value="id"/>
</sas:Object>

Naturally, its also possible to create your own custom implementation of the IObjectDefinitionResolver Objects implementing this interface are used to retrieve an <code>IObjectDefinition</code> for already existing objects to be wired. Useful for <code>IDependencyInjector</code> that have to deal with already existing objects and can't use factory methods. and use your own logic to look up or create a definition for a stage component.

6.1.4.4. Implementing custom autowiring support using the IAutowireProcessor interface

Spring Actionscript wouldn't be Spring Actionscript if it didn't allow you to implement your own brand of autowiring. Naturally the Spring Actionscript team is of the opinion that the offered autowiring functionality is about as broad as one can imagine, but should the need arise to step outside the confines of Spring Actionscript autowiring than this entirely possible.

In this particular case the IAutowireProcessor Interface that needs to be implemented by objects that can perform autowiring on arbitrary objects. is your friend. And as you are used to, its not a very complicated one, see for yourself:

public interface IAutowireProcessor {
	function autoWire(object:Object, objectDefinition:IObjectDefinition = null, objectName:String = null):void;

	function preprocessObjectDefinition(objectDefinition:IObjectDefinition):void;

	function findAutowireCandidateName(clazz:Class):String;
}

The first method is the main autoWire() method that is invoked by the object container immediately after creation.

The second method is invoked by the container right before an object is actually created, so this would typically be a good moment to change any kind of constructor argument autowiring or perhaps change the autowiring strategy of the current IObjectDefinition Describes an object that maintains the configuration for an object's instantiation. based on some pre-configured logic.

As you can see in the default implementation used by the DefaultObjectFactory , (fittingly titled DefaultAutowireProcessor <p>Default <code>IAutowireProcessor</code> implementation.</p> ),it is also possible for your own IAutowireProcessor Interface that needs to be implemented by objects that can perform autowiring on arbitrary objects. implementation to include the IObjectFactoryAware Interface to be implemented by all objects that want to know what container they run in. interface. If your instance implements this particular interface it will automatically be injected by the object factory instance to which the IAutowireProcessor Interface that needs to be implemented by objects that can perform autowiring on arbitrary objects. is assigned.

Now, after you've created your own implementation, its time to hook it up to the object container, typically this would be done something like this:

var applicationContext:ApplicationContext = new ApplicationContext();
applicationContext.autowireProcessor = new MyCustomAutowireProcessor();

After that your own autowiring logic will be performed on any object created by the ApplicationContext Basic implementation of the <code>IApplicationContext</code> interface. No object or factory processors are created by default inside this base class. Use this class for custom configured application contexts. Otherwise use the <code>DefaultApplicationContext</code> which offers some basic functionality 'out-of-the-box'. instance.

Note

Consequently, when you don't need the autowiring functionality at all in your application, it might be an idea to set the autowireProcessor property to null as this will yield a small performance benefit.