我希望使用 groovy 的 invokeMethod 来执行此操作,但事实证明,当您从 Java 调用 Groovy 时,不会调用 invokeMethod,否则它会完美地工作。
我有一个案例,我将 Groovy 类提交给 Java 类(我无法编辑)。Groovy 类是注解的,Java 类扫描注解并将注解的方法保存为它的事件的侦听器。
当事件发出时,我想从事件对象中获取一些信息,使用它来检索数据并将该数据注入脚本中的事件处理程序(通过该方法中的注释变量)。
我可以控制的事情——我实例化脚本,为它们设置一个基类,并将它们传递给另一个系统进行注册。脚本将由其他人编写——我可以控制脚本的设计,但我的目标是简单。
我可能可以创建一个适配器类,但这似乎非常困难和脆弱,因为我必须手动注册所有这些方法,而不是像现在这样使用注释——有很多不同的事件要听。
我想知道是否有我不考虑的常规技巧。我对 groovy 元编程还是很陌生。也许有一种方法可以自动创建适配器类,或者当我编译脚本时,用转发方法替换这些方法,这些方法在调用它们的真实方法之前转发到我的代码——任何可能的事情?
请求的源代码:
源代码——好吧,让我们看看,这个过程分布在几个类中......
这就是我使用 ScriptBase 设置 Groovy 类加载器的方式
cconfig.setScriptBaseClass("tv.kress.bill.minecraft.ezplugin.ScriptBase");
GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader(), cconfig);
然后我将它传递给 Groovy 脚本引擎(我在这里省略了一些东西)
gse = new GroovyScriptEngine(cpString, gcl);
然后我实例化脚本
scriptClass = gse.loadScriptByName(file.getAbsolutePath());
instance = (GroovyObject) scriptClass.newInstance();
然后,如果它是一个“监听器”,它是“罐装”java库用来识别它应该扫描注释的java类的标记接口,我将它传递给该类,以便可以注册任何带注释的方法(沿着某处行“实例”变成了“脚本”,但相同的对象:
if (script instanceof Listener)
pm.registerEvents((Listener) script, this);
脚本本身有趣的部分如下所示:
@EventHandler
public void userEvent(UserInteractEvent event) {
我想添加的是能够在 userEvent 中添加一个带注释的局部变量,如下所示:
@Persist int persistedPerUserData // Or @PersistPerUser? or @Persist(User=true)?
这样就在调用 userEvent 之前,我可以拦截它。我会从 UserInteractionEvent 中获取用户名,将其与脚本、变量和方法名结合起来,以获得一个独特的签名,例如“MyScript:UserEvent:Bill:persistedPerUserData”,并使用它来检索我可以放入persistedPerUserData 的int。
稍后在该方法返回后,从persistedPerUserData 中获取值并将其存储回“MyScript:UserEvent:Bill:persistedPerUserData”(目前是一个哈希,但我希望最终将其设为数据库)。
这样,脚本就不必考虑它正在处理不同用户的事实,它只需要有一组变量并且所有持久性都可以正常工作。
还有其他事件可以使用,但我相信它们都扩展了相同的事件,并且根事件具有“用户”字段。
编辑:就像另一件事不要尝试一样,我尝试像这样使用 ProxyMetaClass/拦截器:
// Attempt (and fail) to intercept calls to an instance of clazz
class Slicer {
public static Object slice(Class clazz) {
Object instance;
def proxy = ProxyMetaClass.getInstance(clazz);
proxy.interceptor = new MyInterceptor();
proxy.use {
instance = clazz.newInstance();
}
return instance;
}
}
使用相同的结果,来自 groovy 类的每个调用都被很好地检测,但没有拦截来自 Java 的调用。回到绘图板。我想这就是 Aspects 使用字节码操作的原因。