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

Nic*_*aly 9 java groovy spring spring-annotations spring-boot

我想使用Spring Framework的动态语言支持,从Groovy脚本创建一个可重新加载的 bean(在运行时!).我想避免xml配置,并在Spring BootApplication上下文中使用注释(或类似).

这是一个扩展的问题,这已经被问,扩展是,我确实希望得到我的手脏BeanPostProcessors,Handlers,Parsers,whatever it takes.

我已经快速浏览了ScriptFactoryPostProcessor的javadoc ,并提出了一些工作示例.我想知道为什么Application.groovy (v2)不起作用?


beans.xml - 有效!(但我想在 Application.groovy中定义bean而不是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>
Run Code Online (Sandbox Code Playgroud)

Application.groovy(v1) - 有效!(但这是一个非常难看的解决方法)

@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()
    }
}
Run Code Online (Sandbox Code Playgroud)

Application.groovy(v2) - 不起作用 - 为什么不呢?

@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")
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来它与在ApplicationContext的生命周期中初始化bean定义的方式/时间有关.我尝试过使用@Order@DependsOn控制bean的顺序 - 无济于事.值得一提的是,我现在重复了以下日志 - 看起来像是ScriptFactoryPostProcessor用"null"bean定义不断覆盖bean(为什么?).

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]
Run Code Online (Sandbox Code Playgroud)

有关:

  • SPR-10253 - 刷新带注释的Groovy控制器会导致ClassCastException
  • SPR-10689 - 版本2.5及更高版本中的标记不适用于可刷新的Spring MVC端点
  • SPR-12300 - 在@Configuration类中添加对动态语言可刷新bean的支持

小智 0

更简单的替代方案:

  • 将 FooBarService 放在类路径上并使用@Component进行注释

或者

  • 在 mybeans.xml 中使用 lang 命名空间

-

<lang:groovy id="foobarService"
    script-source="file:src/main/static/FoobarService.groovy" />
Run Code Online (Sandbox Code Playgroud)

应用程序.groovy

@SpringBootApplication
@ImportResource("classpath:mybeans.xml")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application, args)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的替代方案@slim-l,但不幸的是,您的两个解决方案都没有解决我的问题(它们不是**可重新加载**,除非我弄错了)。您的第一个替代方案不使用[DLS](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/dynamic-language.html)。您的第二个替代方案缺少 `refresh-check-delay="1000"` 属性,并且还使用了我想避免的 `xml` 。 (2认同)