Java中加载Groovy文件及调用其方法

GroovyClassLoader 实战
本文介绍了一种使用GroovyClassLoader加载并执行Groovy脚本的方法。通过实例代码展示了如何从类路径下加载Groovy文件,并调用其内部定义的方法。

本例中,我们会使用GroovyClassLoader来加载groovy脚本。

GroovyClassLoader是一个定制的类装载器,负责解释加载Java类中用到的Groovy类。它也能编译。清单2.21展示了如何使用GroovyClassLoader加载Groovy类并且调用该类的一个方法。

@Component
public class AccessComputeService {

    public static final Logger logger = LoggerFactory.getLogger(AccessComputeService.class);

    private static GroovyClassLoader loader;

    private static final ConcurrentHashMap<String,GroovyObject> groovyObjects = new ConcurrentHashMap<>();

    static {
        PathMatchingResourcePatternResolver resolver = new  PathMatchingResourcePatternResolver();
        loader = new GroovyClassLoader(AccessComputeService.class.getClassLoader());
        try {
            //适配读取classpath下面的*.groovy文件列表
            Resource[] resources = resolver.getResources("classpath:accessScore/*.groovy");
            if(resources==null || resources.length==0){
                logger.warn("未获取到groovy文件");
            }else{
                for (Resource resource: resources) {
                    try ( InputStream inputStream = AccessComputeService.class.getClassLoader().getResourceAsStream("accessScore/" + resource.getFilename())){
                        logger.info("加载准入评分groovy脚本:{}", resource.getFilename());
                        String text = CharStreams.toString(new InputStreamReader(inputStream, "UTF-8"));
                        Class groovyClass = loader.parseClass(text,resource.getFilename());
                        GroovyObject scriptInstance = (GroovyObject)groovyClass.newInstance();
                        groovyObjects.put(resource.getFilename().split("\\.")[0],scriptInstance);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("groovy 引擎初始化失败!!!!!!!!",e);
        }
    }

    public void execute(String scriptFileName, String scriptFunctionName, Map<String, Object> dataMap) {
        //scriptFileName:文件名,scriptFunctionName:文件的方法,dataMap:参数
        Strong result = (String)groovyObjects.get(scriptFileName).invokeMethod(scriptFunctionName, dataMap);
    }
}

 

其他调用groovy的方式

http://blog.youkuaiyun.com/eric_sunah/article/details/11541307

<think> 我们正在讨论Groovy调用Java方法的实现方式。根据引用资料,GroovyJava有很好的互操作性,因为Groovy本身就是运行在JVM上的语言。以下将总结几种常见的Groovy调用Java方法的方式: 1. **直接调用**:因为Groovy兼容Java语法,所以可以直接在Groovy代码中创建Java对象并调用方法。 2. **通过GroovyClassLoader加载Java类**:当Groovy需要动态加载Java类时,可以使用GroovyClassLoader(引用[1]和[2]提到)。 3. **使用GroovyShell执行Java代码片段**(但注意,GroovyShell主要用于执行Groovy脚本,也可以执行混合Java语法的Groovy脚本,但通常不直接用于执行纯Java代码)。 4. **在Groovy中使用Spring Bean**(引用[3]提到)如果Java对象是Spring Bean,Groovy可以通过Spring容器获取Bean并调用方法。 下面我们将详细说明前两种方式(直接调用GroovyClassLoader)并提供代码示例。同时,我们也会提到Groovy调用Java方法时可能出现的异常(如引用[4]所示的MissingMethodException)及其解决方法。 ### 1. 直接调用Groovy中,可以直接像在Java中一样创建Java类的实例并调用方法。这是因为Groovy的语法是Java语法的超集。 **示例:** 假设有一个Java类`HelloJava`: ```java // HelloJava.java public class HelloJava { public void sayHello() { System.out.println("Hello from Java!"); } public static String staticMethod() { return "Static method in Java"; } } ``` 在Groovy脚本中调用: ```groovy // 创建Java对象并调用实例方法 def hello = new HelloJava() hello.sayHello() // 调用静态方法 println(HelloJava.staticMethod()) ``` ### 2. 使用GroovyClassLoader加载Java类 当我们需要动态加载类(比如类名在运行时确定)时,可以使用`GroovyClassLoader`。这种方式特别适合从文件或字符串中加载类(注意:这里加载的是Java类,但GroovyClassLoader原本设计用于加载Groovy类,不过它也能加载Java类,因为Groovy类就是Java类)。 **示例:** 假设我们已经将`HelloJava`类编译成`HelloJava.class`文件,并放在类路径下(或者指定路径)。 ```groovy // 创建GroovyClassLoader def classLoader = new GroovyClassLoader() // 加载HelloJava类(注意:需要全限定类名) Class clazz = classLoader.loadClass("HelloJava") // 创建实例 def obj = clazz.newInstance() // 调用实例方法 obj.sayHello() // 调用静态方法(通过反射) def staticMethod = clazz.getMethod("staticMethod") println(staticMethod.invoke(null)) ``` ### 3. 关于异常MissingMethodException(引用[4]) 在Groovy调用Java方法时,如果方法签名不匹配(比如参数类型或数量不对),Groovy会抛出`MissingMethodException`。例如: ```groovy // 假设Java方法:public void method1(int num) // 但在Groovy调用:method1(30.0) // 传递了double,而Java需要int ``` Groovy是动态类型语言,但调用Java方法时,类型必须兼容。解决方法: - 确保传递的参数类型与Java方法声明的参数类型完全匹配。 - 或者使用Groovy的强制类型转换。 ### 4. 在Groovy中使用Spring Bean(引用[3]) 如果目标Java对象是Spring管理的Bean,可以通过Spring的`ApplicationContext`获取Bean,然后调用方法。 **示例:** 在Groovy脚本中(假设已经有Spring上下文): ```groovy // 获取Spring上下文(具体获取方式取决于你的应用) def ctx = ... // 获取ApplicationContext // 获取Java Bean def myService = ctx.getBean("myService") // 调用方法 myService.doSomething() ``` ### 总结 Groovy调用Java方法非常自然,因为两者都在JVM上运行。主要方式有: - 直接调用(推荐,最简单) - 通过GroovyClassLoader动态加载(适用于类名在运行时确定的情况) - 通过Spring容器获取Bean(在Spring项目中常用) 注意:如果调用时出现`MissingMethodException`,检查方法名是否正确,参数类型和数量是否匹配。 §§相关问题§§ 1. Groovy调用Java方法时,如何处理方法重载? 2. 在Groovy中如何调用Java的静态方法?有哪些注意事项? 3. GroovyJava在类型系统上的主要区别是什么?这些区别如何影响Groovy调用Java方法? </think> ### Groovy调用Java方法实现详解 GroovyJava具有天然的互操作性,以下是常见的调用方式及实现细节: #### 1. **直接实例化调用**(最常用) ```groovy // 导入Java类 import com.example.JavaUtil // 实例化Java类并调用方法 def util = new JavaUtil() def result = util.calculateSum(10, 20) println "计算结果: $result" ``` **特性**: - 完全兼容Java语法和类型系统 - 支持构造函数、实例方法和静态方法调用 - 自动处理基本类型和对象类型转换[^1][^2] #### 2. **通过GroovyClassLoader动态加载** ```groovy // 初始化类加载器 def loader = new GroovyClassLoader() // 加载Java类(需全限定名) Class clazz = loader.loadClass("com.example.DataProcessor") // 创建实例并调用方法 def processor = clazz.newInstance() processor.processData("input.txt") ``` **适用场景**: - 动态加载类路径外的类文件 - 实现插件化架构 - 运行时类加载需求[^2] #### 3. **静态方法调用** ```groovy // 直接调用Java静态方法 import static com.example.MathUtils.square def squaredValue = square(5) // 等效于MathUtils.square(5) println "平方值: $squaredValue" ``` #### 4. **处理Java Bean** ```groovy // Java类 public class User { private String name; // Getter/Setter... } // Groovy操作 def user = new User() user.name = "张三" // 自动调用setName() println "用户名: ${user.name}" // 自动调用getName() ``` **优势**:自动映射属性访问到Getter/Setter方法 --- ### 常见问题解决方案 #### 🔧 异常处理:`MissingMethodException` ```groovy try { new JavaService().undefinedMethod() } catch (MissingMethodException e) { println "方法不存在: ${e.method}" } ``` **原因分析**: - 方法签名不匹配(参数类型/数量) - 方法修饰符不可访问(如private方法) - 类路径配置错误[^4] #### 🔧 类型转换问题 ```groovy // 显式类型声明保证兼容性 int result = new JavaMath().add(5.0 as double, 3.0 as double) ``` --- ### 性能优化建议 1. **避免过度使用GroovyShell**: ```groovy // ❌ 低效方式(每次编译新类) new GroovyShell().evaluate("new JavaService().run()") // ✅ 高效方式(单例实例) def service = new JavaService() service.run() ``` 2. **缓存类加载器实例**: ```groovy // 复用ClassLoader减少开销 static final loader = new GroovyClassLoader() ``` 3. **类型显式声明**: ```groovy // 明确参数类型避免反射开销 String text = new TextParser().parse(document as String) ``` --- ### 实际应用场景 1. **脚本化Java应用**:用Groovy编写测试脚本调用Java核心模块 2. **动态扩展系统**:通过类加载器实现热插拔功能 3. **Spring集成**:在Groovy脚本中注入Spring管理的Java Bean[^3] > 通过合理选择调用方式,Groovy可无缝集成Java生态,同时保留脚本语言的灵活性。对于性能敏感场景,推荐优先使用直接实例化方式并显式声明类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值