Important bug fix in creation of constructor transients using lazy loading. Please update. API and functionality not changed - bug fix only.
Want to see what it is like to let your bean dictate some of its dependency injections? Try out LightWire 0.62. For now it is just for mixin injections and requires you to add a simple cfset in your init() methos rather than adding true annotations and reading them via getmetadata.
The bottom line is that if you'd like to move some (or all) of your bean definitions into your beans a la Google Guice, 0.62 lets you give it a shot.
I'm looking for feedback on how this should work before I implement it in a more elegant manner, but it's tested and working on my sites, so check it out and let me know what you think!
To add mixin injections (in addition to those described in your central bean config) add the following to your init() method (MUST be in the init() method):
Replacing "UserService,ProductService" with a comma delimited list of bean names you want to inject.
I've been looking at Google Guice. At first, I really didn't like the idea of using annotations to provide beans that describe their own DI requirements for my use case.
I use a Software Product Line approach with a single framework for generating all of my sites, and it is not uncommon for me to decide something like: "I'm going to inject another bean called %ObjectName%Mapper into all of my %ObjectName%Service beans". Such a change would be painful to make with annotations as I'd need to edit ALL of my beans in all of my projects. With a central programmatic config file, I can just go into the loop that sets the properties for all business objects and add a single line of code . . .
Get it while it's hot! The main driver for this release was to be more ColdSpring compatible so for a good range of use cases you'll be able to switch seamlessly between DI engines allowing you to late bind the decision on what DI engine to use for a given project (for instance you might prototype with LW and then port to ColdSpring later or vica-versa).
There have been a couple of major API changes to LightWire as well as some improvements under the hood . . . Please note, due to API changes, this is NOT backwards compatible with 0.5 but updating your config beans should only take a minute or two and I think it is more than worth it for the benefits. This should be the last major API change. Find out more about the new API and the new features designed to make it very easy to interchange LightWire with ColdSpring for use cases not requiring AOP, remote bean proxies or autowiring . . .
I finally got a couple of hours to port LightWire to using a config file. It adds one extra file to the project (a BaseConfigObject.cfc), but it makes for a much nicer interface for configuration and would make it trivial to add support for ColdSpring XML files for anyone who wanted to write a small script to loop through an XML file and call the appropriate config methods.
I have full support for constructor, setter and mixin injection and properties, and a nice clean programmatic interface in the config files. I think an enterprising person could also quite easily write a script to go through the config struct exposed by the bean calling getConfigStruct() and turning it into a ColdSpring XML file for easy export of programmatically generated config files as static XML files.
I have also written a little test bed which shows the basic operations of LightWire within a sample project along with the latest copy of LightWire. The one core DI thing still missing is support for using your own factories . I've just not had a use for this personally, but as a proof of concept I'll add optional code to the test harness you can use to use Transfer as a factory within LightWire. That should be in some time tonight if I get another hour to drop it in between paying projects.
The only other thing I see missing (other than AOP and remote bean proxies which I *will* be adding my own take on) is autowiring, which I'm just not into at all and so won't be bloating up the framework with all of the necessary introspection code to implement a solution that I just don't think is a good approach.
Oh, and there is one BIG thing that LightWire is SHAMELESSLY MISSING. It is the perfect kind of project for unit testing and it DOESN'T HAVE ANY TESTS :-< I've read the books, I've downloaded the framework, I understand the benefits, but somehow I'm just still not quite test infected. If any kind soul would be willing to contribute a couple of sample tests to show how they'd go about adding unit tests to this it'd be much appreciated :->
Check out the files in the Subversion repository at http://svn.riaforge.org/lightwire. Latest version is under trunk/LightWire0.5. Or you can download the enclosed zip file below (click on "download").
I've just upgraded LightWire (from version 0.001) to support proper constructor, setter and (the newly defined) mixin injection methods. It handles circular dependencies in all three (or any combination of them), provides lazy loading and has a very simple to use programmatic config file. It is also optimized to inject dependencies into transients as well as singletons and at under 300 lines of code, there is only so much that can go wrong :->
If you’re looking to better understand how Dependency Injection/Inversion of Control works, at under three hundred lines of code it makes perfect sense to at least check out LightWire to see one way to implement a simple DI engine. If you’re just looking for a DI engine off the shelf to solve a problem, I‘ve outlined some of the strengths of LightWire as well as the outstanding priority enhancements and outstanding issues that are less of a priority to give a sense of the current state of play of the LightWire experiment.
Since I'm writing my own Dependency Injection engine (LightWire), I though I might as well blog about the process and the design decisions in case anyone is interested in the thinking required to create a simple DI engine. If anyone notices any design flaws, I’d love to hear about them!!! You can follow along with the code (it’ll be updated before tomorrow morning) at http://lightwire.riaforge.org using either the zip file or the subversion repository.
[UPDATE] Just added all the code to this posting as well, so you can follow along without having to download files!
To get started with LightWire download the LightWire.cfc and the sample LightWireConfig.cfm from the SVN repository. You can place either file anywhere you want. I personally put the cfc in .com.lib (my library directory) and the config file in a "config" directory both of which are below my web root for a given project, but you can put the files anywhere you want.
The structure of this file may change, but right now it seems to be working well for a 0.01 release :-> Any input always appreciated.
Quite some time ago there was a lot of discussion about adding interfaces and constructors and a bunch of other Java-esque features to CF. Apart from the great comments by Jared and Sean on the fact that you don’t NEED a constructor as a language construct (the init() convention is fine), I have one more reason to not want constructors – it makes circular resolution of constructor dependencies impossible.
One of the limitations of ColdSpring is that you can’t have constructor injection of circular dependencies. The reason is (presumably) because ColdSpring follows the Init() convention and treats init() as a genuine constructor. If it treated it as a pseudo constructor (which is what it is), there wouldn’t be a problem.
In LightWire, all of the objects are instantiated (without calling the init method) and then the init method is run in each allowing for circular constructor dependencies because of the fact that init() isn’t a true constructor so I can “create” all of the dependent objects and then immediately afterwards can init() them with their dependencies before returning the requested object. Of course, I probably need to do some thinking about making this thread safe for application scoped objects, but it allows for full or lazy loading and for resolution of circular dependencies even in the “constructor” arguments which seems to me to be pretty cool.
So, please don’t add more limitations to ColdFusion. I like it just the way it is!