Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Spring Dynamic Languages Support from Groovy Configuration

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:

  • SPR-10253 - Refreshing annotated Groovy controllers cause ClassCastException
  • SPR-10689 - tag in version 2.5 and higher doesn't work for refreshable Spring MVC endpoints
  • SPR-12300 - Add support for dynamic languages refreshable beans in @Configuration classes
like image 858
Nick Grealy Avatar asked Aug 25 '15 14:08

Nick Grealy


People also ask

Does spring support Groovy?

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.

Why Is Groovy a dynamic language?

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 .

Which of the following languages can be used to develop application using Spring boot?

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.


1 Answers

Why don't just

@Bean
ScriptFactoryPostProcessor scriptFactory() {
   ScriptFactoryPostProcessor sfpp = new ScriptFactoryPostProcessor()
   sfpp.setDefaultRefreshCheckDelay(1000)
   return sfpp
}
like image 145
techtheist Avatar answered Oct 10 '22 20:10

techtheist