The Mystery of AutoWiring in Model-Glue Unity

I've been playing with Model-Glue Unity on and off over the past few months, and i thought i'd start a blog to help me learn. Maybe i can help a few others learn something too.

One of the things that seems to stump people trying to learn MG is the autowiring feature. Many people might not even know it exists, because it's not very clearly explained in the documentation as of yet. To use autowiring, you need to mess a little with ColdSpring. ColdSpring calls everything by a different name, so that makes it seem kind of foreign in the beginning. A CFC is called a bean, a struct is called a map, an array is called a list, and so on. But once you translate the terms used and get to know your way around a little, it suddenly can seem very easy to use.

Simply put, autowiring is a very handy way to inject instantiated CFC's into your controllers using ColdSpring.

For anyone suffering from ColdSpring phobia (I was too at first. It can easily look like there's too many things to learn at once when starting with MG to jump into ColdSpring and Reactor at the same time), i want to say again that ColdSpring is essentially very simple to use for autowiring. All you need is to understand the advantages in using autowiring, and see an example how to set it up, and you'll be using a very powerful feature of MG in no time.

Autowiring works by default in MG Unity. In MG 1.1, you needed to set some special properties in your ModelGlue.xml file to use autowiring, but this is no longer needed in Unity.

There are several very clear advantages to using autowiring, rather than instantiating your "service" CFC's in your controllers. The first is that it's very clean and simple to use once you understand how it works. As your app grows in size, you'll probably need more and more of these service type CFC's instantiated in your controllers. And you'll probably find yourself using multiple controllers to break your application up into logical chunks. So instead of instantiating an EmailService, for instance, in the init() method of each of your controllers that needs one, you'd just use autowiring to inject the instance of your EmailService that ColdSpring creates for you. It's a much cleaner and more maintainable approach, especially as your app grows.

Another advantage: Sometimes, you may want that one or more of your service CFC's maintains state. Let's assume for a moment that the stateful data is dynamically determined by the app. Think about that a moment. How would you maintain that stateful data in a service across multiple controllers if each controller had a separate instance of that service? That's a big problem that autowiring solves for you in a very simple way.

When MG starts up, ColdSpring creates the CFC instances that you specify in Coldspring.xml and "injects" them into each of your controllers. By inject, i mean that a reference to that instance is passed into the controller. I'll get into the details in a moment, but the important thing to understand here is that when using autowiring, you wind up with the same instance of the service in all your controllers. Which means if one controller alters the state of the service, it's immediately available to all the other controllers. It also means of course that even if state is not a consideration, you avoid having redundant instances instantiated with reduntant code.

Before i go on, maybe it's important to loosely define what i mean by a "service CFC" for some people. Essentially, a service CFC is going to be one that you want to keep in the variables scope of one or more of your controllers. As you probably know, MG's controllers are persisted in the application scope. Hence, any CFC that you inject into a controller using autowiring will also be persisted in application scope.

If you don't want or need a CFC instance to be persisted in one of your controllers, then you can use a Factory to create that instance for you. And yes, ColdSpring can inject that Factory into your controllers for you.

Another advantage to using ColdSpring to manage your services is that you have a one-stop point from which to configure and reconfigure everything. Suddenly find you need your config bean available inside your EmailService? A quick modification to your ColdSpring.xml file does it for you. Need to change the path to your CFC's when you deploy your app? A quick search and replace in your ColdSpring.xml file does the job. You have an overview / control panel for all your CFC dependencies in one place.

Ready to see how autowiring works? Let's look at some code. It's really very easy.

There are 2 steps to setting up autowiring. The first is to add a bean definition in ColdSpring.xml, and the second is to add a setter to the controller that needs an instance of that CFC. ColdSpring uses the term "bean" because it uses the same terminology as is used in Java, but for our purposes, "bean" is equivalent to "CFC". So don't let the term mystify you. Here's what a simple bean definition looks like.

<bean id="AppFactory" class="samasati.model.AppFactory">
...
</bean>

The class property specifies the fully qualified dot path to your CFC, and the id property defines a name for the instance of your CFC.

Once you add a bean definition to your ColdSpring.xml file, then ColdSpring will create an instance of this CFC when your MG app first starts up.

So now we have an instance of samasati.model.AppFactory and it's called "AppFactory". How do we get it in our controller?

Simple. All you need to do is add the following setter to your controller:

<cffunction name="setAppFactory" access="public" returntype="void" output="false">
   <cfargument name="appFactory" required="true">
   <cfset variables.appFactory = arguments.appFactory />
</cffunction>

What happens behind the scenes when MG starts up is that it searches through all the controllers defined in your controllers block in ModelGlue.xml looking for any methods that begin with "set" where the rest of the method name matches the id of a bean defined in ColdSpring.xml. And then MG calls those methods, passing in a reference to the instance of the bean that ColdSpring created.

So in the case above, our bean's id is AppFactory, and the setter in our controller is named setAppFactory. Note that MG automagically calls the method setAppFactory and passes the instance of the CFC that ColdSpring created into the method, but from then on, the method needs to do the rest. Hence the line:

<cfset variables.appFactory = arguments.appFactory />

which of course sets the reference to our appFactory in the variables scope of the controller, effectively persisting it until the application times out.

Now let's move beyond the mechanics of autowiring into some more real life examples and leverage the power of ColdSpring a little along the way. As you may know, Joe provided a simple Configuration bean with MG that's located here: ModelGlue.Bean.CommonBeans.SimpleConfig. If you open it up and take a look at it, you'll see that it simply creates a struct to hold a set of key-value pairs. So let's instantiate a config bean with ColdSpring and autowire that too into our controller.

We're starting off with one controller, but we'll look at a simple way to inject multiple controllers with references to our service CFC's in a bit.

<bean id="AppConfig" class="ModelGlue.Bean.CommonBeans.SimpleConfig">
   <property name="config">
      <map>
         <entry key="dsn"><value>samasati</value></entry>
         <entry key="imagePath"><value>images/</value></entry>
      </map>
   </property>
</bean>

Ok, so again, we've got the class property specifying the fully qualified dot path to the CFC we want to instantiate with ColdSpring, and we've defined the id for the instance as as "AppConfig". So let's open up our controller and add the setter so it's autowired.

<cffunction name="setAppConfig" access="public" returntype="void" output="false">
   <cfargument name="appConfig" required="true">
   <cfset variables.appConfig = arguments.appConfig />
</cffunction>

So far so good. But what's all that property / map / entry business? The short and simple answer is that it's defining a structure called config, with key-value pairs for the dsn and imagePath. Again, it's Java terminology being used. You'll find a more detailed explanation in the ColdSpring documentation online. Maybe it's a good time to give you that url?

http://coldspringframework.org/docs/

I've bookmarked it in my del.icio.us account so i can get to it anytime. What you might want to concentrate on in the beginning is the Bean Factory Reference, specifically the sections covering the bean tag attributes, the bean tag's children, and the children of constructor-arg and property. I think that's all you'd probably need to know to use ColdSping within MG.

Anyway, if we take a look in the documentation for the property tag, we find this definition:

Similar in nature to constructor arg, however in this case ColdSpring will pass some value or object reference into your bean as an argument to a setter method, identified via the name attribute. Thus, your CFC must have a setter method name that matches the property tag's name attribute (for example if your property is named "foo" then your CFC needs a setFoo() method).

Huh? Let's take that one step at a time. As with many things, seeing how it works is much simplier.

In our AppConfig example above, if we open up ModelGlue.Bean.CommonBeans.SimpleConfig we'll find a setter method in there called setConfig which accepts a structure as an argument. Here's what it looks like:

<cffunction name="SetConfig" access="public" return="void" output="false" hint="Set property: config">
   <cfargument name="value" type="struct"/>
   <cfset variables.config = arguments.value />
</cffunction>

Let's look at the ColdSpring code for the bean definition again so we have it right in front of us:

<bean id="AppConfig" class="ModelGlue.Bean.CommonBeans.SimpleConfig">
   <property name="config">
      <map>
         <entry key="dsn"><value>samasati</value></entry>
         <entry key="imagePath"><value>images/</value></entry>
      </map>
   </property>
</bean>

So what's happening when ColdSpring instantiates our AppConfig is that it takes the value of the name defined in the property tag, which is "config", then it looks for a setter in the CFC named "setConfig", and then passes the value of the struct we define within the map tag into the instance using the setConfig() setter. A little complicated, true, but once you get the pattern, it's easy to repeat.

Alright. So now we have a simple config bean that defines our DSN for us among other things, and it's autowired into our controller. But wait a second. It would be really handy if we could pass that config bean into our AppFactory, wouldn't it. Some of the CFC's we might create in our AppFactory might need our DSN.

Here's how we can do that. Let's add a bit to our AppFactory bean definition, like so:

<bean id="appFactory" class="samasati.model.AppFactory">
   <constructor-arg name="appConfig">
      <ref bean="AppConfig" />
   </constructor-arg>
</bean>

Here's what the ColdSpring documentation says about the constructor-arg tag:

This tag will cause Coldspring to supply your bean with a value or object reference when it is instantiated (during a CFC's init() method), passed as an argument named via the name attribute.

Aha! So when there's a contructor-arg tag as a child of a bean tag, ColdSpring looks for an init() method in the CFC, and passes in the arguments defined in the constructor-arg tags. And what's that ref tag about?

I think you must have guessed it. Ref stands for reference. From the ColdSpring documentation: Used to pass in a reference to another bean defined within the BeanFactory. The bean="" attribute references the ID of the other bean.

All we need to do is add a little code to the init method of our AppFactory that accepts an argument called appConfig and sets it in the variables scope. Let's do that:

<cffunction name="init" access="public" output="false">
   <cfargument name="appConfig" required="true">
   <cfset setAppConfig(arguments.appConfig) />
</cffunction>

Now, when our app starts up, ColdSpring instantiates AppConfig, looks for a setter in our CFC called setConfig and passes the struct in that we define within the map tags. Then it instantiates AppFactory, and passes a reference to the instance of AppConfig it already created in an argument called appConfig into the init method of AppFactory. And then it looks for methods called setAppConfig() and setAppFactory in the controllers and if it finds them, passes the instantiated CFC's into those methods.

So far, so good. Now what happens if you have multiple controllers and you want to pass references to all your CFC's that ColdSpring creates into all your controllers?

The simpliest way i've seen is to use a mixin, which is simply a .cfm file that you include in all your controllers that has your autowire setters (and getters) in it. Joe Rinehart, the author of Model-Glue, suggested this approach. Here's what our autowire.cfm file might look like so far, including some getters for our injected CFC's:

<!--- autowire setters and getters --->
<cffunction name="setAppConfig" access="public" returntype="void" output="false">
   <cfargument name="appConfig" required="true">
   <cfset variables.appConfig = arguments.appConfig />
</cffunction>   
<cffunction name="getAppConfig" access="private" output="false">
   <cfreturn variables.appConfig />
</cffunction>   

<cffunction name="setAppFactory" access="public" returntype="void" output="false">
   <cfargument name="appFactory" required="true">
   <cfset variables.appFactory = arguments.appFactory />
</cffunction>
<cffunction name="getAppFactory" access="private" output="false">
   <cfreturn variables.appFactory />
</cffunction>

And then you simply include this file at the top of all your controllers:

<!--- mixins --->
   <cfinclude template="autowire.cfm">

Here's a link to Joe Rinehart's explanation about autowiring on his blog.

So there you have it. I've learned a few things just writing this up. Hopefully it also helps someone along the way. If there's anything i've missed (or misunderstood) about autowiring that you think should be included, add a comment and i'll see about adding it into the main text.

Related Blog Entries

Comments
Nando, that is a great explanation of the autowiring features in Model Glue as well as good use of ColdSpring.

Finally everything in a nice little tutorial!
# Posted By Mark Drew | 9/24/06 5:51 AM
Hey Nando,

Very nice explanation! And more importantly, great to see you blogging. I am looking forwards to seeing great things. You probably also want to get aggregated by fullasagoog and MXNA if you haven't already. This is definitely going to be a blog to watch!!!

Best Wishes,
Peter
# Posted By Peter Bell | 9/27/06 2:25 AM
Thanks for this. I still haven't been able to fully get CS in terms of MG yet, and this helps tremendously.
# Posted By Raymond Camden | 9/27/06 9:09 AM
It's a really nice post, though I do not completely agree with the use of autowiring. Autowiring examines functions metadata for init properties and settings, and tries to wire your components together. This does not happen when model-glue initializes, but when you get an instance of a bean for the first time. In your case, if you define setters in your controllers, it will happen when ColdSpring initializes those controllers.

Using autowiring is a dangerous tool, because defining dependencies in the ColdSpring XML helps to document your application. If you rely on autowiring, without looking at getters and setters in each bean, there is no way for you to know about dependencies. We were talking at CFUnited about making ColdSpring generating an XML with the autowiring dependencies, and making it available for you to look at, or copy/paste into your main XML.

Injecting services into your controllers is not the only solution for maintaining state. By default, all ColdSpring beans are singletons and you can get their instance inside the Model-Glue controllers by calling "cfset var AppFactory = getModelGlue().getBean('AppFactory')". Nevertheless, because the controllers are not being defined in ColdSpring.xml, if you absolutely need/want services to be injected, you would need to reply on autowiring.

The use of autowiring and mixins is a clever idea, but you're adding complexity and you're saving in code is transforming getModelGlue().getBean('AppFactory') into getAppFactory(). By doing this, you're also forcing ColdSpring to initialize your services onLoad, and not on first use. ... so tell me, is it really worth it?
# Posted By Rob Gonda | 10/2/06 10:25 AM
Excellent explanation. I've been somewhat avoiding ColdSpring until I've had some free time to wrap my head around it and this post provides a great first read about how to interact with itand what's going on behind the scenes. Thanks!
# Posted By Allen Leis | 10/2/06 10:55 AM
Thanks for the most informative post Nando - I wish there were more tutorials like this floating around on the net for Model Glue Unity.

I was never clear on what auto-wiring accomplished for me and your tut clears up a lot of the fuzziness - a must read for MG:U developers!
# Posted By Craig McDonald | 10/2/06 3:31 PM
Hey Rob,

I think i get your point. I think you are saying that when using autowiring, your dependencies are not documented in your ColdSpring.xml, and one of the main points behind ColdSpring is to document your dependencies all in one place, in the ColdSpring.xml. Am i understanding you correctly?

Even so, as things stand, i believe you'd still need to look in your controllers to understand their dependencies, even if you didn't use autowiring.

I like the points you raised about getModelGlue().getBean('AppFactory'). I'd like to include this in the main text about autowiring, if you don't mind.

As far as whether it's "worth it", it all depends on the use case. But it's a good point overall to be aware of. It seems you are saying that if you have a service that takes a long time to load for a certain, perhaps specialized area of your app, it might be better to use cfset var myTimeConsumingService = getModelGlue().getBean('myTimeConsumingService') in the specific controller function it's needed in, and let ColdSpring load that service as a singleton, which it does by default, on first use.

Great stuff. Thanks for leaving the comment!
# Posted By Nando | 10/3/06 5:57 PM
Got my point across indeed. ColdSpring.xml documents your object dependencies. Pay special attention in the word 'object'... The way I see it, ColdSpring wires your models together, and your controllers, well, should not be part of your business logic. You should not have to look into your controllers to understand dependencies, because they're not even part of it. You can better understand flow, perhaps, but that's a different story.

The controller layer should be as dumb as possible; if you think about it, all it's doing it routing events... The presentation layer asks for an action to be performed, the controller route the call to the business logic layer, and then forward that information back to the presentation layer. That said, no dependencies are ever created in the controller layer.

If you can accomplish this, you should be able to reuse your business logic and presentation layer using any front controller (MG, MII, FB).

HTH
# Posted By Rob Gonda | 10/3/06 7:46 PM
Well ... in my mind, ModelGlue.xml is the dumb controller in MG, and that's pretty well enforced by the limitations of MG's XML language. Hmmm? What more could we ask for?

What i note here is that if someone wants to keep their controller CFC's as dumb as possible and abstract everything out to a reuseable service layer because they have a good reason to do that, well they can. MG doesn't prevent you from doing that. If it did, then i would say there's a problem. But since it doesn't ... well, "good" architecture can't be enforced through a framework anyway. It can only be suggested. At some point, you have to give the developer a free hand to do what they will.
# Posted By Nando | 10/3/06 9:17 PM
Thank you. Your article was very useful in helping me understand ColdSpring.
# Posted By Richard | 10/9/06 9:59 AM
Hey Rob,
As far as whether it's "worth it", it all depends on the use case. But it's a good point overall to be aware of. It seems you are saying that if you have a service that takes a long time to load for a certain, perhaps specialized area of your app, it might be better to use cfset var myTimeConsumingService = getModelGlue().getBean('myTimeConsumingService') in the specific controller function it's needed in, and let ColdSpring load that service as a singleton, which it does by default, on first use.
# Posted By al | 4/11/07 11:31 AM
Thanks for the most informative post Nando - I wish there were more tutorials like this floating around on the net for Model Glue Unity.

I was never clear on what auto-wiring accomplished for me and your tut clears up a lot of the fuzziness - a must read for MG:U developers!
# Posted By jaguarcardealer | 6/12/07 1:41 PM
nice plugin thanks
# Posted By evden eve nakliyat | 10/18/07 9:47 AM
Thank You for another very interesting article. Its really good written and I fully agree with You on main issue, btw. I must say that I really enjoyed reading all of Your posts. Its interesting to read ideas


http://www.onlineshop-artikelverzeichnis.de/Access...
http://www.onlineshop-artikelverzeichnis.de/Auto
http://www.onlineshop-artikelverzeichnis.de/Bueche...
http://www.onlineshop-artikelverzeichnis.de/Buero
http://www.onlineshop-artikelverzeichnis.de/Comput...
http://www.onlineshop-artikelverzeichnis.de/Ernaeh...
http://www.onlineshop-artikelverzeichnis.de/Erotik...
http://www.onlineshop-artikelverzeichnis.de/Essen
http://www.onlineshop-artikelverzeichnis.de/Finanz...
http://www.onlineshop-artikelverzeichnis.de/Freize...
http://www.onlineshop-artikelverzeichnis.de/Garten...
http://www.onlineshop-artikelverzeichnis.de/Geld
http://www.onlineshop-artikelverzeichnis.de/Gesche...
http://www.onlineshop-artikelverzeichnis.de/Gesund...
http://www.onlineshop-artikelverzeichnis.de/Handy
http://www.onlineshop-artikelverzeichnis.de/Haus
http://www.onlineshop-artikelverzeichnis.de/Haushalt" target="_blank">http://www.onlineshop-artikelverzeichnis.de/Hausha...
http://www.onlineshop-artikelverzeichnis.de/Heimwe...
http://www.onlineshop-artikelverzeichnis.de/Hobby
http://www.onlineshop-artikelverzeichnis.de/Kinder...
http://www.onlineshop-artikelverzeichnis.de/Kleidu...
http://www.onlineshop-artikelverzeichnis.de/Koerpe...
http://www.onlineshop-artikelverzeichnis.de/Kunst
http://www.onlineshop-artikelverzeichnis.de/Lifest...
http://www.onlineshop-artikelverzeichnis.de/Mode
http://www.onlineshop-artikelverzeichnis.de/Multim...
http://www.onlineshop-artikelverzeichnis.de/Musik
http://www.onlineshop-artikelverzeichnis.de/Online...
http://www.onlineshop-artikelverzeichnis.de/Reisen...
http://www.onlineshop-artikelverzeichnis.de/Schmuc...
http://www.onlineshop-artikelverzeichnis.de/Schnae...
http://www.onlineshop-artikelverzeichnis.de/Softwa...
http://www.onlineshop-artikelverzeichnis.de/Spiele...
http://www.onlineshop-artikelverzeichnis.de/Sport
http://www.onlineshop-artikelverzeichnis.de/Tiere
http://www.onlineshop-artikelverzeichnis.de/Trinke...
http://www.onlineshop-artikelverzeichnis.de/Versan...
# Posted By Artikelverzeichnis | 10/21/07 3:51 PM
good Infos!
# Posted By boxbandagen | 11/3/07 1:41 PM
Good explanation it was very useful for understand ColdSpring.
# Posted By rollos | 11/8/07 1:36 AM
Thanks for the most informative post Nando - I wish there were more tutorials like this floating around on the net for Model Glue Unity.

I was never clear on what auto-wiring accomplished for me and your tut clears up a lot of the fuzziness - a must read for MG:U developers!
# Posted By Plissee | 12/7/07 2:55 PM
Very nice article. Thanks for taking the time to write it down. Keep up the good work.
# Posted By Gira | 1/2/08 10:52 AM
There are many useful informations in this article. Thanks and greetings from Thuringia!
# Posted By Kunstforum | 1/10/08 3:16 AM
Good stuff. Thanks and greetings!
# Posted By Kunstforum | 1/18/08 3:05 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.1.004.