Dynamically create Spring beans from groovy scripts at runtime
Marius Hanganu

In the current project - a java based CMS - we were faced with an interesting problem: how can we dynamically create renderers to power our blocks in the html page (currently all renderers are Java classes and Spring beans also described in the application context files).
Imagine the power of this approach. Especially when Java deployments can be quite a hassle in a multi server environment (deploying sources on the linux machines, wait for a good moment for starting/stopping the servers - which may or may not perform a sensitive operation at that time, synchronize the restart of the web servers, check log files for any errors, etc).
What could be better than having your Spring beans dinamically created from the administration panel? No server restarts, no deployments. Just keep your Groovy scripts in the database and make any modification realtime.
Achieving the programatic creation of Spring beans from groovy scripts can be done in four steps:
2. create a bean definition using the previously loaded class
3. inject any other beans into your bean definition
4. register the bean definition and get a handle on the bean created
Of course, you cannot declare variables as instances of the Java class defined in the groovy script. Or you may do it programatically through reflection. But it is much simpler (if the project suits these needs) to have a base interface for all your dynamic beans and after those 4 steps, simply cast the bean created to the Java interface. So you might add two more steps to the previous four:
5. cast the created bean to the base interface so that you can use it in your code
The code is actually pretty simple. But you can hardly find any article/post on the subject. Most of them discuss an older version of Spring (1.x), while my code had to work with Spring 2.0.x - which is completely different in terms of the API calls needed to create a bean.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class GroovyTemplateEngineImpl extends DefaultListableBeanFactory implements ApplicationContextAware { public BaseInterface createOrUpdateBean(String rendererName, String code) throws Exception, ClassNotFoundException { // 1. load the groovy script and parse it into a class GroovyClassLoader gcl = new GroovyClassLoader(getClassLoader()); Class clazz = gcl.parseClass(groovyScriptAsAString); // 2. create the bean definition AbstractBeanDefinition beanDef = BeanDefinitionReaderUtils.createBeanDefinition( "parentBean", packageName + "." + className, gcl); // 3. inject here any attributes that would normally be passed using spring XML configuration files beanDef.setAttribute("attr1", bean1); DefaultListableBeanFactory factory = (DefaultListableBeanFactory) appCtx.getAutowireCapableBeanFactory(); // 4. Create the bean - I'm using the class name as the bean name factory.registerBeanDefinition(className, beanDef); Object bean = factory.createBean(clazz, AUTOWIRE_BY_NAME, false); // 5. further on you can cast it to any interface return (BaseInterface) bean; } } |
You will also need to add to the previous class a setter for application context to be injected (the class needs to implement ApplicationContextAware).
Please note that this code only works from spring version 2.0.3 and up. If you’re using a lower version, you’ll likely encounter this exception:
1 2 3 | Caused by: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException: warning can't determine implemented interfaces of missing type .... [Xlint:cantFindType] |
Good luck groovying!
Posted in Java, General |

February 25th, 2010 at 6:02 pm
I could not get the following to work:
beanDef.setAttribute(”attr1″, bean1);
The following alternative worked for me:
MutablePropertyValues v = new MutablePropertyValues();
v.addPropertyValue(”attr1″,bean1);