全部产品

Java

更新时间:2017-09-14 19:29:29   分享:   

函数计算目前支持以下Java运行环境:

  • OpenJDK 1.8.0 (runtime = java8)

在函数计算服务使用Java编程,需要定义一个类并实现函数计算预定义的接口,一个最简单的函数定义如下:

  1. package example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.StreamRequestHandler;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. public class HelloFC implements StreamRequestHandler {
  8. @Override
  9. public void handleRequest(
  10. InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
  11. outputStream.write(new String("hello world").getBytes());
  12. }
  13. }
  1. 包名/类名
    • 包名和类名可以是任意的,但是需要与创建函数时的”Handler”字段相对应:上面的例子包名是”example”,类名是”HelloFC”,那么创建函数时指定的Handler为example.HelloFC::handleRequest,”Handler”的格式为{package}.{class}::{method}
  2. 实现的接口
    • 用户的代码中必须要实现函数计算预定义的接口。上面的例子中实现了StreamRequestHandler,其中的inputStream参数是调用函数时传入的数据,outputStream用于返回函数的执行结果。关于函数接口的更详细的介绍参考下面的函数接口
  3. context参数
    • context参数中包含一些函数的运行时信息(例如request id/临时AK等)。其类型是com.aliyun.fc.runtime.Context,具体结构和使用在下面的使用context介绍
  4. 返回值
    • 实现StreamRequestHandler接口的函数通过outputStream参数返回执行结果

其中用到的com.aliyun.fc.runtime这个包的依赖可以通过下面的pom.xml引用:

  1. <dependency>
  2. <groupId>com.aliyun.fc.runtime</groupId>
  3. <artifactId>fc-java-core</artifactId>
  4. <version>1.0.0</version>
  5. </dependency>

在创建函数之前,用户需要将代码和依赖的fc-java-core编译成jar包,如果使用IntelliJ IDEA,可以参考这篇文章,编译成jar包后就可以使用fcli或者控制台上传代码,以fcli为例:

  1. rockuw-MBP:hello-java (master) $ ls -lrt
  2. total 16
  3. -rw-r--r-- 1 rockuw staff 7690 Aug 31 19:45 hellofc.jar
  4. >>> mkf hello-java -t java8 -h example.HelloFC::handleRequest -d ./functions/hello-java
  5. >>> invk hello-java
  6. hello world
  7. >>>

进阶使用

使用context

context是函数计算在运行时生成的一个对象,其中包含一些运行时的信息,用户在代码中可以使用这些信息。context的类型是object,其定义如下,具体实现可以在这里找到:

  1. package com.aliyun.fc.runtime;
  2. public interface Context {
  3. public String getRequestId();
  4. public Credentials getExecutionCredentials();
  5. public FunctionParam getFunctionParam();
  6. public FunctionComputeLogger getLogger();
  7. }

可以看到context中包含了4个信息:

  1. RequestId: 本次调用请求的唯一id,用户可以把它记录下来在出现问题的时候方便调查
  2. FunctionParam: 当前调用的函数的一些基本信息如函数名/函数入口/函数内存/超时时间
  3. ExecutionCredentials: 函数计算服务通过扮演用户提供的服务角色获得的一组临时密钥,其有效时间是5分钟。用户可以在代码中使用它去访问相应的服务(例如OSS),这就避免了用户把自己的AK信息写死在函数代码里。
  4. Logger: 函数计算封装过的logger,见下面的使用logging

例如下面的代码使用临时密钥,向OSS中上传了一个文件:

  1. package example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.Credentials;
  4. import com.aliyun.fc.runtime.StreamRequestHandler;
  5. import com.aliyun.oss.OSSClient;
  6. import java.io.ByteArrayInputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.OutputStream;
  10. public class HelloFC implements StreamRequestHandler {
  11. @Override
  12. public void handleRequest(
  13. InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
  14. String endpoint = "oss-cn-shanghai.aliyuncs.com";
  15. String bucketName = "my-bucket";
  16. Credentials creds = context.getExecutionCredentials();
  17. OSSClient client = new OSSClient(
  18. endpoint, creds.getAccessKeyId(), creds.getAccessKeySecret(), creds.getSecurityToken());
  19. client.putObject(bucketName, "my-object", new ByteArrayInputStream(new String("hello").getBytes()));
  20. outputStream.write(new String("done").getBytes());
  21. }
  22. }

使用logging

用户的函数通过context.getLogger()打印的内容会被收集到用户在创建Service时指定的LogStore中:

  1. package example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.StreamRequestHandler;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. public class HelloFC implements StreamRequestHandler {
  8. @Override
  9. public void handleRequest(
  10. InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
  11. context.getLogger().info("hello world");
  12. outputStream.write(new String("hello world").getBytes());
  13. }
  14. }

上面的代码输出的日志内容是:

  1. message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO] hello world

使用context.getLogger().warncontext.getLogger().error分别可以打包WARN/ERROR级别的日志。

函数接口

用户在使用Java编程时,必须要实现一个类,它要实现函数计算预定义的接口,目前有2个预定义的接口可以实现:

  1. StreamRequestHandler以流的方式接受调用输入(event)和返回执行结果,用户需要从inputStream中读取调用函数时的输入,处理完成后把函数执行结果写入到outputStream中来返回;本文最开始的例子使用的就是这个接口
  2. PojoRequestHandler<I, O>通过泛型的方式,用户可以自定义输入和输出的类型,但是它们必须是POJO类型。下面将举例如何使用这个接口
  1. // HelloFC.java
  2. package example;
  3. import com.aliyun.fc.runtime.Context;
  4. import com.aliyun.fc.runtime.PojoRequestHandler;
  5. public class HelloFC implements PojoRequestHandler<SimpleRequest, SimpleResponse> {
  6. @Override
  7. public SimpleResponse handleRequest(SimpleRequest request, Context context) {
  8. String message = "Hello, " + request.getFirstName() + " " + request.getLastName();
  9. return new SimpleResponse(message);
  10. }
  11. }
  1. // SimpleRequest.java
  2. package example;
  3. public class SimpleRequest {
  4. String firstName;
  5. String lastName;
  6. public String getFirstName() {
  7. return firstName;
  8. }
  9. public void setFirstName(String firstName) {
  10. this.firstName = firstName;
  11. }
  12. public String getLastName() {
  13. return lastName;
  14. }
  15. public void setLastName(String lastName) {
  16. this.lastName = lastName;
  17. }
  18. public SimpleRequest() {}
  19. public SimpleRequest(String firstName, String lastName) {
  20. this.firstName = firstName;
  21. this.lastName = lastName;
  22. }
  23. }
  1. // SimpleResponse.java
  2. package example;
  3. public class SimpleResponse {
  4. String message;
  5. public String getMessage() {
  6. return message;
  7. }
  8. public void setMessage(String message) {
  9. this.message = message;
  10. }
  11. public SimpleResponse() {}
  12. public SimpleResponse(String message) {
  13. this.message = message;
  14. }
  15. }

准备调用的输入文件:

  1. {
  2. "firstName": "FC",
  3. "lastName": "aliyun"
  4. }

使用fcli调用结果:

  1. >>> invk hello-java -f /tmp/a.json
  2. {"message":"Hello, FC aliyun"}
  3. >>>

使用自定义的模块

如果用户需要使用自定义的模块,则需要在编译成jar包时,将它们与代码一起打包,并且勾选“解压至目标JAR”。下面将演示如何将OSS java SDK打包进来。

1. 在pom.xml中添加对OSS java SDK的依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.aliyun.fc.runtime</groupId>
  4. <artifactId>fc-java-core</artifactId>
  5. <version>1.0.0</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.aliyun.oss</groupId>
  9. <artifactId>aliyun-sdk-oss</artifactId>
  10. <version>2.6.1</version>
  11. </dependency>
  12. </dependencies>

2. 配置导出jar包的选项:

java1

java2

java3

导出jar包之后就可以创建函数了:

  1. rockuw-MBP:hello-java (master) $ ls -lrth
  2. total 6520
  3. -rw-r--r-- 1 rockuw staff 3.2M Aug 31 21:03 hellofc.jar
  4. rockuw-MBP:hello-java (master) $ jar -tf hellofc.jar | head
  5. Picked up _JAVA_OPTIONS: -Duser.language=en
  6. META-INF/MANIFEST.MF
  7. example/
  8. example/HelloFC.class
  9. example/SimpleRequest.class
  10. example/SimpleResponse.class
  11. META-INF/
  12. META-INF//
  13. org/
  14. org//
  15. org/apache/

错误处理

用户的函数在执行过程如果抛出异常,那么函数计算会把异常捕获并将异常信息返回。例如下面的代码:

  1. package example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.StreamRequestHandler;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.OutputStream;
  7. public class HelloFC implements StreamRequestHandler {
  8. @Override
  9. public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
  10. throw new IOException("oops");
  11. }
  12. }

调用时收到的响应为:

  1. >>> invk hello-java -f /tmp/a.json
  2. {
  3. "errorMessage" : "oops",
  4. "errorType" : "java.io.IOException",
  5. "errorCause" : "oops",
  6. "stackTrace" : [ "example.HelloFC.handleRequest(HelloFC.java:15)" ]
  7. }
  8. Error: Request id: 45dd8d90-6b78-cce3-087c-8bf4ebc6c9af. Error type: UnhandledInvocationError

发生异常时,函数调用的响应的HTTP header中会包含X-Fc-Error-Type: UnhandledInvocationError

本文导读目录
本文导读目录
以上内容是否对您有帮助?