Using Spring Dynamic Languages Support from Java Configuration

前端 未结 2 1883
太阳男子
太阳男子 2021-01-18 01:52

I\'d like to use Dynamic Languages Support of Spring Framework.

In XML I\'d just use the lang namespace, but I\'d like to use Java configuration (i.e. <

相关标签:
2条回答
  • 2021-01-18 01:55

    I'm going down the same path (work in progress), and have managed to initialise reloadable Groovy scripts by adding the bean definitions when the Spring Application is prepared. In my example I'm using spring-boot.

    If you add the following AddBeanDefinitionsListener listener class and a ScriptFactoryPostProcessor bean, you can initialise Groovy scripts with very little effort...

    AddBeanDefinitionsListener.groovy

    public class AddBeanDefinitionsListener 
            implements ApplicationListener<ApplicationPreparedEvent> {
    
        Map<String, BeanDefinition> beanDefs
    
        AddBeanDefinitionsListener(Map<String, BeanDefinition> beanDefs) {
            this.beanDefs = beanDefs
        }
    
        @Override
        void onApplicationEvent(ApplicationPreparedEvent event) {
            def registry = (BeanDefinitionRegistry) event.applicationContext
                    .autowireCapableBeanFactory
            beanDefs.each { String beanName, BeanDefinition beanDef ->
                registry.registerBeanDefinition(beanName, beanDef)
            }
        }
    
        /* Static Utility methods */
    
        static BeanDefinition groovyScriptFactory(String scriptLocation) {
            def bd = BeanDefinitionBuilder.genericBeanDefinition(GroovyScriptFactory)
                    .addConstructorArgValue(scriptLocation)
                    .getBeanDefinition()
            bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, 1000)
            bd
        }
    
    }
    

    Application.groovy

    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication app = new SpringApplication(Application)
            app.addListeners(new AddBeanDefinitionsListener([
                    'foobar0': groovyScriptFactory("file:/some/path/Foobar0Service.groovy"),
                    'foobar1': groovyScriptFactory("file:/some/path/Foobar1Service.groovy")
            ]))
            app.run(args)
        }
    
        @Bean
        ScriptFactoryPostProcessor scriptFactory() {
            new ScriptFactoryPostProcessor()
        }
    
    }
    

    (Might be nicer if implemented with Spring 4.2's events?)

    0 讨论(0)
  • 2021-01-18 02:04

    Why don't you ask us directly by email? :-)

    I see that XML Lang support is relly magic. There is enough stuff which is based on BeanDefinition and its attributes. In additional there are some hooks with ProxyFactory and CGLIB for the lang:property.

    What I see for the JavaConfig is some Java class wrapper for the ScriptEvaluator and RefreshableResourceScriptSource from Spring Integration:

    @ContextConfiguration
    @RunWith(SpringJUnit4ClassRunner.class)
    public class RefreshableScriptJavaConfigTests {
    
        @Autowired
        private Calculator calculator;
    
        @Test
        public void testGroovyRefreshableCalculator() {
            assertEquals(5, this.calculator.add(2, 3));
        }
    
        @Configuration
        public static class ContextConfiguration {
    
            @Value("classpath:org/springframework/integration/scripting/config/jsr223/Calculator.groovy")
            private Resource groovyScriptResource;
    
            @Bean
            public ScriptEvaluator groovyScriptEvaluator() {
                return new GroovyScriptEvaluator();
            }
    
            @Bean
            public Calculator calculator() {
                return new Calculator(new RefreshableResourceScriptSource(this.groovyScriptResource, 1000));
            }
    
        }
    
        public static class Calculator {
    
            private final ScriptSource scriptSource;
    
            @Autowired
            private ScriptEvaluator scriptEvaluator;
    
            public Calculator(ScriptSource scriptSource) {
                this.scriptSource = scriptSource;
            }
    
            public int add(int x, int y) {
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("x", x);
                params.put("y", y);
                return (int) this.scriptEvaluator.evaluate(this.scriptSource, params);
            }
    
        }
    
    }
    

    Where the Calculator.groovy is:

    x + y
    

    I understand that it isn't so flexible as it looks with interfaces and configuration from XML definition, but at least it will help you to see where we are.

    Feel free to raise a JIRA issue on the matter and we'll see what we can do here. Something like @EnableScripting and @ScriptSource(refreshDelay = 1000) on the Resource @Bean method.

    I think for now you can just @Import some XML snippets with lang definitions.

    Cheers, Artem

    0 讨论(0)
提交回复
热议问题