Created
September 22, 2015 22:01
-
-
Save thomasdarimont/9fe86c61208c340e875a to your computer and use it in GitHub Desktop.
Example for refreshable Groovy Scripts via Java Config. RefreshableGroovyScript is a FactoryBean that produces Proxies backed by a RefreshableTargetSource. Changes in the groovy script are picked up after the configured time interval.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package demo; | |
import static java.util.concurrent.TimeUnit.*; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.context.annotation.Bean; | |
@SpringBootApplication | |
public class App { | |
public static void main(String[] args) throws Exception { | |
Evaluator evaluator = SpringApplication.run(App.class, args).getBean(Evaluator.class); | |
for (int i = 0; i < 20; i++) { | |
System.out.printf("evaluated to %s%n", evaluator.evaluate(null)); | |
SECONDS.sleep(1); | |
} | |
} | |
@Bean | |
public RefreshableGroovyScript evaluator() { | |
return new RefreshableGroovyScript("classpath:GroovyEvaluator.groovy", Evaluator.class).refreshEvery(1, SECONDS); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package demo; | |
public interface Evaluator { | |
boolean evaluate(Object arg); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class GroovyEvaluator implements demo.Evaluator{ | |
def boolean evaluate(arg) { | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>demo</groupId> | |
<artifactId>spring-boot-groovy-reloading-demo</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<packaging>jar</packaging> | |
<name>spring-boot-groovy-reloading-demo</name> | |
<description>Demo project for Groovy reloading Spring Boot</description> | |
<parent> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-parent</artifactId> | |
<version>1.3.0.M5</version> | |
<relativePath /> <!-- lookup parent from repository --> | |
</parent> | |
<properties> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
<java.version>1.8</java.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-aop</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.codehaus.groovy</groupId> | |
<artifactId>groovy</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-maven-plugin</artifactId> | |
</plugin> | |
</plugins> | |
</build> | |
<repositories> | |
<repository> | |
<id>spring-snapshots</id> | |
<name>Spring Snapshots</name> | |
<url>https://repo.spring.io/snapshot</url> | |
<snapshots> | |
<enabled>true</enabled> | |
</snapshots> | |
</repository> | |
<repository> | |
<id>spring-milestones</id> | |
<name>Spring Milestones</name> | |
<url>https://repo.spring.io/milestone</url> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</repository> | |
</repositories> | |
<pluginRepositories> | |
<pluginRepository> | |
<id>spring-snapshots</id> | |
<name>Spring Snapshots</name> | |
<url>https://repo.spring.io/snapshot</url> | |
<snapshots> | |
<enabled>true</enabled> | |
</snapshots> | |
</pluginRepository> | |
<pluginRepository> | |
<id>spring-milestones</id> | |
<name>Spring Milestones</name> | |
<url>https://repo.spring.io/milestone</url> | |
<snapshots> | |
<enabled>false</enabled> | |
</snapshots> | |
</pluginRepository> | |
</pluginRepositories> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package demo; | |
import java.time.Duration; | |
import java.time.temporal.ChronoUnit; | |
import java.util.concurrent.TimeUnit; | |
import org.springframework.aop.TargetSource; | |
import org.springframework.aop.framework.ProxyFactory; | |
import org.springframework.aop.support.DelegatingIntroductionInterceptor; | |
import org.springframework.beans.factory.FactoryBean; | |
import org.springframework.beans.factory.InitializingBean; | |
import org.springframework.core.io.DefaultResourceLoader; | |
import org.springframework.core.io.FileSystemResource; | |
import org.springframework.core.io.Resource; | |
import org.springframework.scripting.ScriptFactory; | |
import org.springframework.scripting.ScriptSource; | |
import org.springframework.scripting.groovy.GroovyScriptFactory; | |
import org.springframework.scripting.support.ResourceScriptSource; | |
class RefreshableGroovyScript implements FactoryBean<Object>, InitializingBean { | |
private Object delegate; | |
private Duration refreshInterval = Duration.ZERO; | |
private String scriptLocation; | |
private Class<?> type; | |
public RefreshableGroovyScript(String scriptLocation, Class<?> type) { | |
this.scriptLocation = scriptLocation; | |
this.type = type; | |
} | |
@Override | |
public Object getObject() { | |
return delegate; | |
} | |
@Override | |
public Class<?> getObjectType() { | |
return type; | |
} | |
@Override | |
public boolean isSingleton() { | |
return true; | |
} | |
public Duration getRefreshInterval() { | |
return refreshInterval; | |
} | |
public void setRefreshInterval(Duration refreshInterval) { | |
this.refreshInterval = refreshInterval; | |
} | |
public RefreshableGroovyScript withRefreshEvery(Duration duration) { | |
setRefreshInterval(duration); | |
return this; | |
} | |
public RefreshableGroovyScript refreshEvery(int amount, TimeUnit timeUnit) { | |
setRefreshInterval(Duration.of(amount, ChronoUnit.valueOf(timeUnit.name()))); | |
return this; | |
} | |
@Override | |
public void afterPropertiesSet() throws Exception { | |
this.delegate = createPotentiallyRefreshableDelegate(createRefreshableTargetSource()); | |
} | |
private Object createPotentiallyRefreshableDelegate(SimpleRefreshableScriptTargetSource srsts) { | |
return refreshInterval == Duration.ZERO ? srsts.freshTarget() : createRefreshableProxy(srsts); | |
} | |
private SimpleRefreshableScriptTargetSource createRefreshableTargetSource() { | |
Resource resource = new DefaultResourceLoader().getResource(scriptLocation); | |
ScriptFactory factory = new GroovyScriptFactory(resource instanceof FileSystemResource ? "file" : "classpath"); | |
ScriptSource script = new ResourceScriptSource(resource); | |
SimpleRefreshableScriptTargetSource srsts = new SimpleRefreshableScriptTargetSource(script, factory); | |
srsts.setRefreshCheckDelay(refreshInterval.toMillis()); | |
return srsts; | |
} | |
private Object createRefreshableProxy(SimpleRefreshableScriptTargetSource srsts) { | |
ProxyFactory proxyFactory = new ProxyFactory(); | |
proxyFactory.setTargetSource(srsts); | |
proxyFactory.setInterfaces(type); | |
DelegatingIntroductionInterceptor introduction = new DelegatingIntroductionInterceptor(srsts); | |
introduction.suppressInterface(TargetSource.class); | |
proxyFactory.addAdvice(introduction); | |
return proxyFactory.getProxy(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package demo; | |
import java.io.IOException; | |
import org.springframework.aop.target.dynamic.AbstractRefreshableTargetSource; | |
import org.springframework.scripting.ScriptCompilationException; | |
import org.springframework.scripting.ScriptFactory; | |
import org.springframework.scripting.ScriptSource; | |
class SimpleRefreshableScriptTargetSource extends AbstractRefreshableTargetSource { | |
private final ScriptSource script; | |
private final ScriptFactory factory; | |
public SimpleRefreshableScriptTargetSource(ScriptSource script, ScriptFactory factory) { | |
this.script = script; | |
this.factory = factory; | |
} | |
@Override | |
protected Object freshTarget() { | |
try { | |
return factory.getScriptedObject(script); | |
} catch (ScriptCompilationException | IOException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Would be nice to have a complete maven directory structure - at least in the download zip.