"ColdSpring is a framework for ColdFusion Components, inspired by the Spring Framework for Java, and its core focus is to manage the dependencies within your CFC "model." (2). ColdSpring has been around for several years now, but I'd not really used it on a project yet. However, recently I took over the maintenance of a very large ColdSpring/Mach-II application and also am working with the Kansas City user group on creating a new user group web site that is using ColdSpring and Model-Glue. So I needed to get smart on ColdSpring and how to use its many features.
A review of the ColdSpring documentation and tutorials on the web showed that there were not many code examples with explanations of how to use ColdSpring at the "grade school" level. If Dave Ross, Chris Scott, Sean Corfield, and others are at the doctorate level, I'm still in 3rd (maybe 4th) grade in my ColdSpring education. Also many of the available examples have ColdSpring wrapped up in a framework such as Mach-II or Model-Glue. Of course, ColdSpring is very useful in complex applications that have lots of inter dependent CFCs, which is when you're also probably going to use one of the common frameworks like Mach-II.
But I think to learn ColdSpring and what it can do, it is helpful for someone at the grade school level to look at the code for a simple application that just uses ColdSpring's basic functions. Trying to learn ColdSpring and Mach-II (or Model-Glue) together can be daunting for our young and delicate minds. Also our attention span as grade schoolers is a bit shorter than those graduate level folks.
So my goal with this blog post is to provide you some very basic code and notes that explain a simple introductory use of ColdSpring. If people find this blog entry useful, I'll build on it in the future with code that shows how to use other ColdSpring features.
What This Blog Entry is Not
This is not the place to debate why we should or should not use ColdSpring. This is also not the place to learn how to create CFCs or the use of Service, Gateway, DAO, and Bean CFCs. There are many excellent resources for those concepts. I'm also not covering why or how a CFC can be dependent on one or more other CFCs (see reference 3 below for a good introduction to that concept and why ColdSpring is useful).
This is most definitely not the place to get answers to your ColdSpring questions. See reference 1 for places you can post your ColdSpring questions and (maybe) get answers from the PhDs of ColdSpring. Remember, I'm just trying to get through ColdSpring grade school right now.
If you have a specific question or comment about this example and my code, please do post a comment. If you know of a good ColdSpring tutorial (not those wrapped up also in another framework) please post a link.
What Do You Need To Have and Know
You need to understand how to write and create CFCs. You should be familiar with the concept of using a Service CFC to be the "front-end" of your model. This basic example uses UserService and UserDAO CFCs. The UserService is our application programming interface (API) and all requests for information about a user or group of users by the CFM pages goes through the UserService CFC. The UserDAO CFC is used for data access. Note that neither the UserService or UserDAO CFCs are complete. There is just enough code in each CFC to illustrate this example.
You need either MySQL or Microsoft Access. The SQL to create and populate the tblUser (the database table used by this example) in a MySQL database is found in the data folder of the code download. There is also a Microsoft Access database with a tblUser in the data folder. You must create a datasource in the ColdFusion administrator that connects ColdFusion to whichever database you use. In my example I called the datasource that connects to the MySQL database "justCSdbMySQL" and the datasource that connects to the Access database "justCSdbAccess."
Of course you need the ColdSpring framework files. Use reference 1 below to download those files and place the ColdSpring folder in your web root.
Setup The Example Code
Download the example code zip file. You will need to extract the files to where you put ColdSpring in your web root. You should extract my code example zip files to the coldspring/examples folder (the examples folder is included in the ColdSpring framework download. If you've done this successfully, you should have a folder named JustColdSpring in ColdSpring/Examples.
Make sure you have a working datasource that connects ColdFusion to either the MySQL or Access database described above. If the name of that datasource is not "justCSdbMySQL" then you'll have to change this line in the file services.xml:
If you've done everything correctly then you should be able to run the index.cfm file (for example:
http://localhost:8500/coldspring/examples/justcoldspring/index.cfm?reloadapp) and see Bruce Phillips in the rendered page.
Explaining The Example Code
<cfapplication name="JustColdSpring" />
<!---setup the ColdSpring bean factory and setup the beans defined in services.xml.
The bean factory object name is beanFactory.
The beanFactory will only be placed into application scope once unless reloadApp URL
<cfif not structKeyExists(application,"beanFactory") or structKeyExists(url,"reloadApp")>
<cflock name="JustColdSpring" timeout="25">
<cfif not structKeyExists(application,"beanFactory") or structKeyExists(url,"reloadApp")>
<!---create the beanFactory object in application scope by calling the
DefaultXMLBeanFactory CFC's init method--->
<cfset application.beanFactory =
<!---read the services.xml file and create CFC objects for each bean defined in the
Let's start by looking at the application.cfm file. After I give the application a name, I need to check whether or not ColdSpring has been used to create the beanFactory object.
Think of a ColdSpring BeanFactory as the container, or holder, for your application's components. It will instantiate, configure, and resolve the dependencies among the components (beans) you place inside it. (4)
The BeanFactory is the heart of ColdSpring. A beanFactory object resides in application scope and we can use it throughout our ColdFusion application to get a reference to our CFC objects (which ColdSpring refers to as beans in the services.xml file [see below]). If the beanFactory object doesn't already exist in application scope (or if the URL variable reloadApp exists) I have the ColdSpring CFC DefaultXmlBeanFactory call its init method to create a BeanFactory object that I store in application.beanFactory. I then call the BeanFactory CFC's loadBeans function, passing it the file name of services.xml.
Remember, all the above is only done the first time the application is run. If I later make changes to one of the CFCs being managed by the beanFactory object, then I need to be sure to have a URL variable named reloadApp in the URL to force the code to redo the creation of the beanFactory object. Otherwise the changes I've made to a CFC will not be available to the running application.
<?xml version="1.0" encoding="UTF-8"?>
defines beans (CFC objects)
resolves dependencies between the CFCs
<!-- these properties refer to other beans that are (or will be) defined)
the UserService CFC must have a setUserDAO function. That function will
receive a userDAO object created by ColdSpring (see bean with id of userDAO
<!--ColdSpring will create a userDAO object and pass it to the UserService CFC's
setUserDAO method (see code above)-->
<!-- we'll explicitly pass in the datasource name to the init constructor
the init function must have a cfargument named dsn
justCSdbMySQL should point to the MySQL database or
you could use justCSdbAccess which should point to the Access database -->
The services.xml file is used to tell ColdSpring what CFC objects (bean) we need for our application and also what dependencies exist between the CFCs.
The second bean above with the id attribute of userDAO tells ColdSpring to create a UserDAO object using the CFC given in the class attribute. The contructor-arg tag tells ColdSpring that the UserDAO's init method has a cfargument with the name of dsn and ColdSpring should send the value justCSdbMySQL to the init method for that dsn argument's value. See the UserDAO (in the model folder) for the init function. ColdSpring expects the UserDAO CFC to have an init method, which acts as a kind of constructor for the CFC.
So the UserDAO is depending upon a value being sent to its init method so that the variables.dsn property gets a value that the rest of the functions in the UserDAO CFC may use. ColdSpring has resolved this dependency for us.
Look over the first bean (id="userService") defined in the services.xml file. This bean definition tells ColdSpring to create a userService object using the UserService CFC given in the class attribute. The property tag tells ColdSpring to call the setUserDAO function in the UserService CFC and send as argument to that function the userDAO object (the one created by the second bean definition and identified by the id value of userDAO).
If you examine the code for UserService CFC you'll see that it is dependent on knowing an object of type UserDAO so that it can call the UserDAO's read function (see function getUserByID). The UserService CFC has a setUserDAO function that is used to provide the variables.m_userDAO property with a UserDAO object that can then be used in all the other functions of UserService. ColdSpring resolves this dependency for us by how we've defined the userService bean in the services.xml file.
Note that when you use the property tag to tell ColdSpring how to resolve a dependency, ColdSpring expects there to be a set function that matches up with the name attribute. So our UserService CFC must have a setUserDAO function.
<cfset userService = application.beanFactory.getBean('userService')>
<cfinvoke component="#userService#" method="getUserByID" returnvariable="user">
<cfinvokeargument name="userID" value="1">
<cfdump var="#user#" />
To get a reference to a CFC object being managed by ColdSpring you can use the beanFactory method getBean and send it the name (the id value you setup in services.xml) of the CFC object you want. So my userService variable above refers to the userService CFC object being managed by ColdFusion. This UserService object will have had its dependencies resolved as specified in the services.xml file.
Once I have a reference to the CFC object, I can call its methods as normal. So in the above code I use cfinvoke to call the getUserByID method and the query object returned by the getUserByID method is stored in the variable user.
Points to Note
My UserDAO and UserService CFCs are ignorant of ColdSpring. Except for using an init function as a constructor (which is regarded as a CFC best practice), ColdSpring makes no requirements of the CFCs. I could very easily reuse these two CFCs in an application that doesn't use ColdSpring.
Remember, if you change a CFC, then you must include the URL variable reloadApp to force ColdSpring to recreate the beanFactory in application scope.
ColdSpring is capable of much more than resolving dependencies between CFCs. As we advance from grade school, to middle school and beyond, we'll become better able to use ColdSpring's features. This basic tutorial is just an introduction of how to use ColdSpring naked, outside of another framework like Model-Glue.
Let me know if this tutorial was useful for you, if you'd like me to continue posting basic ColdSpring tutorials, or if something I've written needs better explanation.
Time for recess!
- ColdSpring Framework, http://www.coldspringframework.org/
- ColdFusion Developer's Journal Special "Frameworks" Focus Issue: ColdSpring; http://coldfusion.sys-con.com/read/176181.htm
- The Blog of Andy Jarrett, ColdSpring and Dependency Injection for the beginner part 1
- ColdSpring Online Documentation, http://www.coldspringframework.org/docs/
- Example Code For This Blog Entry, http://www.brucephillips.name/blog/justcoldspring.zip