Since I started using Gaelyk, one of the features I missed most (coming from a Grails background) is Spring’s dependency injection. Until recently I didn’t even know if it was possible to use Spring in Google App Engine, so I decided to do a little investigation on the subject, and found out that it’s very easy indeed.
Here’s a little tutorial on how to configure Spring in your Gaelyk project. I’m assuming you have basic knowledge of Spring, Gaelyk and Maven.
First, let’s create a Gaelyk project. The easiest way is using the excellent maven-gaelyk archetype:
1
|
|
Now open the project in your favorite IDE, so we can edit the configuration files. First, add the Spring dependency to your pom.xml
:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
Next we need to configure Spring’s ContextLoaderListener in web.xml
:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
As you can see from above, we configured Spring to load all context configuration files under the directory WEB-INF/spring
.
With these configurations in place, your project is already Spring enabled. Now we need a easy way to access the
Spring’s Application Context. One good way to do this is using a singleton that implements the ApplicationContextAware
interface. To keep this post as small as possible, I borrowed an implementation from
this blog post, where you can learn
more about the details. Create the directory src/main/groovy
and put the following SpringApplicationContext singleton
there (in the correct package):
package com.deluan.gaelyk;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Wrapper to always return a reference to the Spring Application Context from
* within non-Spring enabled beans. Unlike Spring MVC's WebApplicationContextUtils
* we do not need a reference to the Servlet context for this. All we need is
* for this bean to be initialized during application startup.
*
* Original from http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
*/
public class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
/**
* This method is called from within the ApplicationContext once it is
* done starting up, it will stick a reference to itself into this bean.
* @param context a reference to the ApplicationContext.
*/
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
/**
* This is about the same as context.getBean("beanName"), except it has its
* own static handle to the Spring context, so calling this method statically
* will give access to the beans by name in the Spring application context.
* As in the context.getBean("beanName") call, the caller must cast to the
* appropriate target class. If the bean does not exist, then a Runtime error
* will be thrown.
* @param beanName the name of the bean to get.
* @return an Object reference to the named bean.
*/
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
public static ApplicationContext getContext() {
return CONTEXT;
}
}
Configure the singleton in your spring context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="springApplicationContext" class="com.deluan.gaelyk.SpringApplicationContext"/>
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy/MM/dd" />
</bean>
<bean id="timeFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="hh:mm:ss" />
</bean>
<bean id="dateTimeFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy/MM/dd hh:mm:ss" />
</bean>
</beans>
As you can see, I also declared some SimpleDateFormat instances as beans to be used in our examples.
Now everything is configured and ready to be used. Let’s see how we can obtain a spring bean inside a Groovlet.
Create the file WEB-INF/groovy/index.groovy
with the following content:
import com.deluan.gaelyk.SpringApplicationContext
def dateFormat = SpringApplicationContext.getBean('dateFormat')
def now = new Date()
println dateFormat.format(now)
Now run your application with the command mvn gae:run
, point your browser to http://localhost:8080/index.groovy and
you should see something like this:
Well, that’s it! Nothing much different from what you are used to do in a normal Web application, right? But remember: Gaelyk is NOT your normal Web framework so let’s spice things a little bit.
The solution for looking up beans depicted above is a bit cumbersome. Let’s use
Gaelyk’s plugin system to make things a little more “groovy”.
Using the plugin descriptor bellow, we can provide shortcuts to our SpringApplicationContext’s methods, getContext()
and getBean(). Save it in the file WEB-INF/plugins/spring.groovy
:
import com.deluan.gaelyk.SpringApplicationContext
binding {
appCtx = SpringApplicationContext.context
getBean = {
SpringApplicationContext.getBean(it)
}
autowire = { self, beanNames ->
beanNames.each {
self.setProperty(it, SpringApplicationContext.getBean(it))
}
}
}
Before you can use these shortcuts, you need to tell Gaelyk about your descriptor by “installing” it in your project.
Save the code bellow in the file WEB-INF/plugins.groovy
:
install spring
Now you can use the shortcuts in your Groovlets this way:
def now = new Date()
// Simple context lookup
def dateFormat = getBean('dateFormat')
// Resolve a list of bean names and create bindings for each one of them
autowire this, ['timeFormat', 'dateTimeFormat']
html.html {
body {
p appCtx.displayName // Access the ApplicationContext
p dateFormat.format(now)
p timeFormat.format(now)
p dateTimeFormat.format(now)
}
}
Cool, isn’t it? A note on the autowire
binding: It creates bindings “automagically” for each bean you passed as a
parameter, as if the beans were declared in your Groovlet.
You can download the sample project used in this post from GitHub: http://github.com/deluan/gaelyk-spring. You can follow each commit to see exactly what was changed in each step of this tutorial.
If you have any suggestion or question, please let me know.
UPDATE: I’ve refactored the autowire
method into a Category, so now it’s not necessary to pass this
as the first
parameter. The new version is available at GitHub