I'd like to use Dynamic Languages Support of Spring Framework, to create a reloadable bean (at runtime!) from a Groovy script. I want to avoid xml
configuration, and use annotations (or similar) within a Spring Boot
Application context.
This is an extension to a question that's already been asked, the extension being that I DO want to get my hands dirty with BeanPostProcessors
, Handlers
, Parsers
, whatever it takes
.
I've had a quick look at the javadoc for ScriptFactoryPostProcessor, and have come up with working examples. I want to know why Application.groovy (v2)
doesn't work?
beans.xml - works! (but I want to define the beans in Application.groovy instead of xml
...)
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor">
<property name="defaultRefreshCheckDelay" value="1000" />
</bean>
<bean id="foobar0" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="file:/C:/someDir/src/main/static/FoobarService.groovy"/>
</bean>
Application.groovy (v1) - works! (but is a very ugly workaround)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application)
// Add GroovyScriptFactory after Application is prepared...
app.addListeners(new ApplicationListener<ApplicationPreparedEvent>() {
void onApplicationEvent(ApplicationPreparedEvent event) {
def registry = (BeanDefinitionRegistry) event.applicationContext.autowireCapableBeanFactory
def bd = BeanDefinitionBuilder.genericBeanDefinition(GroovyScriptFactory)
.addConstructorArgValue("file:/C:/someDir/src/main/static/FoobarService.groovy")
.getBeanDefinition()
bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, 1000)
registry.registerBeanDefinition('foobar0', bd)
}
})
app.run(args)
}
@Bean
ScriptFactoryPostProcessor scriptFactory() {
new ScriptFactoryPostProcessor()
}
}
Application.groovy (v2) - doesn't work - why not?
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application, args)
}
@Bean
ScriptFactoryPostProcessor scriptFactory() {
new ScriptFactoryPostProcessor()
}
@Bean
GroovyScriptFactory foobar0() {
new GroovyScriptFactory("file:/C:/someDir/src/main/static/FoobarService.groovy")
}
}
It looks like it's something to do with how/when the beans definitions are initialised in the the lifecycle of an ApplicationContext. I've tried using @Order
and @DependsOn
to control bean ordering - to no avail. Worth mentioning, I'm now getting the following log repeated - which looks like the ScriptFactoryPostProcessor
is continually overwriting the bean with a "null" bean definition (why?).
2015-08-27 12:04:11.312 INFO 5780 --- [ main] o.s.b.f.s.DefaultListableBeanFactory :
Overriding bean definition for bean 'scriptFactory.foobar0': replacing [Generic bean: class [null];
scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; p
rimary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=n
ull] with [Generic bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=0; depen
dencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; i
nitMethodName=null; destroyMethodName=null]
Related:
In Spring Integration 2.0, we added Groovy support, letting you use the Groovy scripting language to provide the logic for various integration components — similar to the way the Spring Expression Language (SpEL) is supported for routing, transformation, and other integration concerns.
Groovy is dynamically-typed and determines its variables' data types based on their values, so this line is not required. The code above should create the variable number with a value of 5 , then change its value to 10 by adding 15 to it and dividing it by 2 .
First of all, it makes use of Java, which is one of the most popular programming languages in the world. Besides that, Spring Boot is an amazing tool that helps you to get enterprise-grade applications up and running quickly without having to worry about configuring your application correctly and safely.
Why don't just
@Bean
ScriptFactoryPostProcessor scriptFactory() {
ScriptFactoryPostProcessor sfpp = new ScriptFactoryPostProcessor()
sfpp.setDefaultRefreshCheckDelay(1000)
return sfpp
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With