使用Java配置中的Spring动态语言支持

时间:2014-10-05 22:48:27

标签: spring spring-java-config

我想使用Spring Framework的Dynamic Languages Support

在XML中,我只使用lang命名空间,但我想使用Java配置(即@Configuration类)。< / p>

我可以想象我可以通过从org.springframework.scripting.config package,inc初始化所有地狱来做到这一点。他们创建的所有BeanPostProcessorHandlerParserFactoryBean,但我真的不想去那里。

还有其他方法吗?如果没有,那么从Groovy脚本创建可重新加载的bean所需的最小配置是什么?

2 个答案:

答案 0 :(得分:7)

您为什么不直接通过电子邮件询问我们? : - )

我看到XML Lang的支持非常神奇。有足够的内容基于BeanDefinition及其attributes。另外,ProxyFactory有一些CGLIBlang:property的钩子。

我在JavaConfig中看到的是来自Spring IntegrationScriptEvaluatorRefreshableResourceScriptSource的一些Java类包装器:

@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);
        }

    }

}

Calculator.groovy的位置:

x + y

我知道它不像从XML定义的接口和配置看起来那么灵活,但至少它会帮助你看到我们的位置。

随意提出有关此问题的JIRA问题,我们将看到我们可以在这里做些什么。类似于@EnableScripting @ScriptSource(refreshDelay = 1000)方法的Resource@Bean

我认为现在您只需@Import一些带有lang定义的XML代码段。

干杯, 阿尔乔姆

答案 1 :(得分:2)

我正在进行down the same path(正在进行中),并且已经设法通过在准备Spring应用程序时添加bean定义来初始化可重新加载的Groovy脚本。在我的示例中,我使用spring-boot

如果添加以下AddBeanDefinitionsListener侦听器类和ScriptFactoryPostProcessor bean,则可以轻松地初始化Groovy脚本...

<强> 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()
    }

}

(如果用Spring 4.2's events实施,可能会更好吗?)