我们正在为 groovy 脚本寻找一种包含机制,以便为横切关注点留出空间。
在我的示例中,我们将 Web 服务端点作为 groovy 脚本并希望登录到我们的 Web 服务协议。为此,我们使用隐式对象(从我们的框架中获取)来创建日志记录语句。
但如果我们在每个 Web 服务端点中编写代码,这就是样板代码。
我们正在 php 中搜索 include() 之类的东西,其中包括其他 groovy 脚本,有什么想法可以做到这一点吗?
我们正在为 groovy 脚本寻找一种包含机制,以便为横切关注点留出空间。
在我的示例中,我们将 Web 服务端点作为 groovy 脚本并希望登录到我们的 Web 服务协议。为此,我们使用隐式对象(从我们的框架中获取)来创建日志记录语句。
但如果我们在每个 Web 服务端点中编写代码,这就是样板代码。
我们正在 php 中搜索 include() 之类的东西,其中包括其他 groovy 脚本,有什么想法可以做到这一点吗?
Groovy 将其文件视为对象(将其视为自动包装)。它使 java 类路径中的所有 .groovy 文件都可以作为类使用。因此,如果您有 util.groovy 文件,其中包含以下内容:
def static AuxMethod() {
return "Hello World"
}
要从另一个文件中调用它,您只需编写:
println util.AuxMethod()
就是这样。同样,只需确保您的 util.groovy 文件位于类路径中。
要从当前脚本调用脚本u.groovy
,将原始参数传递给 u.groovy,运行
run(new File('u.groovy'), args)
显然,您还可以发送任何您想要的字符串参数:
run(new File('u.groovy'),
['one', new File('two.text').absolutePath] as String[])
既然您已经提到了“横切关注点”,我想说您需要拦截您的 Web 服务调用AOP样式(不是包含机制)。
Grails 与Spring 框架完全集成,因此这为利用 Spring AOP 特性提供了一个很好的选择。从 grails 官方指南中查看本章:http: //grails.org/doc/latest/guide/14.%20Grails%20and%20Spring.html并搜索单词 AOP。
也许有一种纯粹的 AOP 方式,但我会选择 grails 和 spring。
我针对我正在创建的领域特定语言对此进行了一些研究。有三种可能:
将您的类创建为继承父 groovy 类。将您的共享代码放在基类中。
使用 ScriptBaseClass 参见http://groovy.codehaus.org/Embedding+Groovy。这是一个将在其上创建所有脚本的类。
使用导入静态方法功能。请注意,您可以在 java 容器中执行此操作(请参阅http://mrhaki.blogspot.com/2011/06/groovy-goodness-add-imports.html)。
所有这些工作都很棒。我的首选是 ScriptBaseClass。如果公共代码是 Groovy,这效果最好(ScriptBaseClass必须是 groovy 类。它不能是 java 类。)
当然,对于所有这些项目,您仍然需要在 groovy 代码中实际调用公共方法。例如:
doCommonStuff();
.
. do the rest of it here
.
这不是太可怕,我不认为。当然与添加某种#include 预处理器语句大致相同。
最后,所有这些都假设您可以访问调用 Groovy 代码的 java 程序。如果不是这种情况,您仍然可以使用静态导入。这只是额外的一行代码。
import static com.mycompany.mycode.doCommonStuff
doCommonStuf()
.
. do the rest of it here
.
我发现这个邮件列表很有帮助。 http://groovy.329449.n5.nabble.com/Groovy-scripts-Reusing-declared-methods-in-other-scripts-How-Include-td5703723.html
我为我的脚本创建了一个预处理器。它搜索特定include
模式,这是一个示例:
public final class IncludePreprocessor {
@FunctionalInterface
public interface IncludeLoader {
InputStream load(String include) throws IOException;
}
private static final Pattern INCLUDE_PATTERN = Pattern.compile("include\\s+(.+)$");
private final IncludeLoader includeLoader;
public IncludePreprocessor(IncludeLoader includeLoader) {
this.includeLoader = includeLoader;
}
public boolean preprocess(InputStream mainScript, Writer outputScript) throws IOException {
boolean preprocessed = false;
try (Scanner sc = new Scanner(mainScript)) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
Matcher m = INCLUDE_PATTERN.matcher(line);
if (m.matches()) {
outputScript.append("//").append(line).append(System.lineSeparator());
String include = m.group(1);
try (InputStream in = includeLoader.load(include)) {
StringWriter sw = new StringWriter();
preprocess(in, sw);
outputScript.append(sw.toString()).append(System.lineSeparator());
preprocessed = true;
}
outputScript.append("//").append(line).append(" [EOF]").append(System.lineSeparator());
} else {
outputScript.append(line).append(System.lineSeparator());
}
}
}
return preprocessed;
}
}
以及如何使用它:
//common.groovy
def sum(a,b) {
a + b
}
// main.groovy
include common.groovy
sum(1,2)
// Demo.java
public class Demo {
public static void main(String[] args) {
IncludePreprocessor ip = new IncludePreprocessor(include -> new FileInputStream("./" + include));
StringWriter sw = new StringWriter();
ip.preprocess(new FileInputStream("./main.groovy", sw));
System.out.println(sw.toString());
}
}