All Products
Search
Document Center

Java Interface

Last Updated: Jun 25, 2019

When you use Java to write the code in Function Compute, you must first define a Java function handler. You can use generic handlers or HTTP trigger handlers based on whether the Java runtime environment supports HTTP triggers. HTTP trigger handlers are different from generic handlers because they need to process the input HTTP requests and return responses with custom HTTP headers. Generic handlers include function handlers and initialize handlers.

This topic introduces the generic handlers and HTTP trigger handlers.

Generic handlers

Function handlers

When you use Java to compile, you must first implement the predefined interfaces provided by Function Compute. Function Compute currently provides two predefined interfaces:

  1. StreamRequestHandlerThis interface uses the stream type to process the input event data and return the execution result. The input data is bound to inputStream and the execution result is bound to outputStream.

  2. PojoRequestHandlerThis interface uses the POJO types, allowing you to customize the input and output of the handler. Both the input and output must be the POJO type.

StreamRequestHandler

The following code defines a simple function:

  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. Package and class names

You can assign any name to a package or class. However, the names must be referenced in the “Handler” field of the function to be created. In the preceding example, the package name is “example” and the class name is “HelloFC”. Therefore, the “Handler” field must be set to example.HelloFC:handleRequest. The format of the “Handler” field is {package}.{class}::{method}.

2. Interface implementation

You must implement the interface predefined by Function Compute in your code. In the preceding example, the interface StreamRequestHandler is implemented. The parameter inputStream of the handler is bound to the input data and the parameter outputStream is bound to the execution result.

3 .Context

A context contains the runtime information of the function, such as the request ID and the temporary AccessKey set. The type of the context is com.aliyun.fc.runtime.Context.

4. Returned values

A function that implements the StreamRequestHandler interface returns execution results through the outputStream parameter.

5. Reference the interface repository

The dependency of the com.aliyun.fc.runtime package can be referenced in the following pom.xml:

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

You can click maven repository to obtain the latest fc-java-core version.

Before you create a function, you must package the code and its dependency fc-java-core into a JAR file. For more information, see Java code packaging. After you package the code, use fcli or the Function Compute console to upload the package. The following example shows how to use fcli to upload the package:

  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. >>>

The hello world code in the preceding example is packaged into a JAR sample package. You can use this sample code package for testing purpose.

PojoRequestHandler

The following code defines a simple function:

  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. }

Prepare an input file for invoking the function:

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

Use fcli to invoke the function. The following information is returned:

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

Initialize handlers

Whether your function uses the stream type for input and output or uses POJO types to customize the input and output, when you add an initializer interface to the Java runtime, you must first implement the predefined initializer interface.

The predefined initializer interface is as follows:

  1. package com.aliyun.fc.runtime;
  2. import java.io.IOException;
  3. public interface FunctionInitializer {
  4. /**
  5. * The interface to handle a function compute initialize request
  6. *
  7. * @param context The function compute initialize environment context object.
  8. * @throws IOException IOException during I/O handling
  9. */
  10. void initialize(Context context) throws IOException;
  11. }

The following demo contains an initialize handler and a simple function that uses the stream type:

  1. package aliyun.serverless.test.example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.FunctionComputeLogger;
  4. import com.aliyun.fc.runtime.StreamRequestHandler;
  5. import com.aliyun.fc.runtime.FunctionInitializer;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.io.OutputStream;
  9. public class InitializerAndStreamRequest implements StreamRequestHandler, FunctionInitializer {
  10. @Override
  11. public void initialize(Context context) {
  12. FunctionComputeLogger logger = context.getLogger();
  13. logger.debug(String.format("RequestID is %s %n", context.getRequestId()));
  14. }
  15. @Override
  16. public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
  17. FunctionComputeLogger logger = context.getLogger();
  18. logger.debug(String.format("RequestID is %s %n", context.getRequestId()));
  19. output.write(new String("hello world!").getBytes());
  20. output.flush();
  21. }
  22. }

The newly added initialize method for InitializerAndStreamRequest is the initializer interface. It has the following features:

1. Package and class names

Same as a function handler, you can assign any name to the package and class of the initialize handler. The format of the initialize handler is {package}.{class}::{method}. However, the method called in the function handler is handleRequest, while the method called in the initialize handler is initialize. According to the definition, the initialize handler in this example is aliyun.serverless.test.example.InitializerAndStreamRequest::initialize.

2. Interface implementation

You must implement the interface predefined by Function Compute in your code. In the preceding example, the FunctionInitializer interface is implemented. The initializer interface has only one Context parameter.

3 . Context

A context contains the runtime information of the function, such as the request ID and the temporary AccessKey set. The type of the context is com.aliyun.fc.runtime.Context.

4. Returned values

A function that implements the FunctionInitializer interface does not return any values.

The following demo contains an initialize handler and a function that uses the custom POJO types for input:

  1. package aliyun.serverless.test.example;
  2. import com.aliyun.fc.runtime.Context;
  3. import com.aliyun.fc.runtime.PojoRequestHandler;
  4. import com.aliyun.fc.runtime.FunctionInitializer;
  5. import com.aliyun.fc.runtime.FunctionComputeLogger;
  6. public class InitializerAndPojoRequest implements FunctionInitializer,PojoRequestHandler<SimpleRequest, SimpleResponse> {
  7. @Override
  8. public void initialize(Context context) {
  9. FunctionComputeLogger logger = context.getLogger();
  10. logger.debug(String.format("RequestID is %s %n", context.getRequestId()));
  11. }
  12. @Override
  13. public SimpleResponse handleRequest(SimpleRequest request, Context context) {
  14. FunctionComputeLogger logger = context.getLogger();
  15. logger.debug(String.format("RequestID is %s %n", context.getRequestId()));
  16. String message = "Hello, " + request.getFirstName() + " " + request.getLastName();
  17. return new SimpleResponse(message);
  18. }
  19. }

HTTP trigger handlers

For more about HTTP triggers, see HTTP triggers.

HTTP trigger handler interface

Function Compute provides a Servlet-based HTTP trigger handler. Its interface is as follows:

  1. Public interface HttpRequestHandler {
  2. /**
  3. * The entrance function of fc http trigger
  4. * @param request The servlet request
  5. * @param response The servlet response
  6. * @param context The fc context
  7. * @throws IOException If IO exception happened
  8. * @throws ServletException If servlet exception happened
  9. */
  10. public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) throws IOException, ServletException;
  11. }

To use the HTTP trigger, you must update the version of the fc-java-core repository to 1.3.0and later.

HTTP trigger demo

  1. package com.aliyun.fc.example;
  2. import java.io.IOException;
  3. import java.io.OutputStream;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import com.aliyun.fc.runtime.Context;
  8. import com.aliyun.fc.runtime.HttpRequestHandler;
  9. public class Hello implements HttpRequestHandler {
  10. public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
  11. throws IOException, ServletException {
  12. String requestPath = (String) request.getAttribute("FC_REQUEST_PATH");
  13. String requestURI = (String) request.getAttribute("FC_REQUEST_URI");
  14. String requestClientIP = (String) request.getAttribute("FC_REQUEST_CLIENT_IP");
  15. response.setStatus(200);
  16. response.setHeader("header1", "value1");
  17. response.setHeader("header2", "value2");
  18. String body = String.format("Path: %s\n Uri: %s\n IP: %s\n", requestPath, requestURI, requestClientIP);
  19. OutputStream out = response.getOutputStream();
  20. out.write((body).getBytes());
  21. out.flush();
  22. out.close();
  23. }
  24. }
1. HttpServletRequest

The HTTP trigger handler interface of Function Compute uses the standard Servlet protocol. A user request is encapsulated into the HttpServletRequest object. User request parameters and the request header can be obtained through this object. In addition, Function Compute encapsulates some attributes into the HttpServletRequest object. You can call the GetAttribute method to query these attributes. The attributes include the following:

  • FC_REQUEST_PATH

    The path of the request.

  • FC_REQUEST_URI

    The URI of the request.

  • FC_REQUEST_CLIENT_IP

    The client IP address of the request.

2. HttpServletResponse

You can use the standard HttpServletResponse object to return the response header and body.

3 .Context

A context contains the runtime information of the function, such as the request ID and the temporary AccessKey set. The type of the context is com.aliyun.fc.runtime.Context.

HTTP triggers support traditional Web applications.

Traditional Web applications based on the Servlet protocol can be easily migrated to the Function Compute platform. Currently, mainstream frameworks including Spring, SpringBoot, and Struts2 are supported. The following example shows how to use the fc-java-common repository provided by Function Compute to load Web applications.

  1. Package your Web project and generate the demo.war package

  2. Upload the demo.war package to an OSS bucket, for example, demo-bucket.

  3. Create a function, and then create an initialize handler and a function handler.

    • The sample code of the function is as follows:

      1. package com.aliyun.fc.example;
      2. import java.io.IOException;
      3. import javax.servlet.ServletException;
      4. import javax.servlet.http.HttpServletRequest;
      5. import javax.servlet.http.HttpServletResponse;
      6. import com.aliyun.fc.runtime.Context;
      7. import com.aliyun.fc.runtime.FcAppLoader;
      8. import com.aliyun.fc.runtime.FunctionComputeLogger;
      9. import com.aliyun.fc.runtime.FunctionInitializer;
      10. import com.aliyun.fc.runtime.HttpRequestHandler;
      11. public class HelloWeb implements FunctionInitializer, HttpRequestHandler {
      12. private FcAppLoader fcAppLoader = new FcAppLoader();
      13. private String ossEndPoint = "YourOSSEndPoint";
      14. private String bucket = "YourOSSBucket";
      15. private String key = "YourWarName";
      16. private String userContextPath = "/2016-08-15/proxy/{YourServiceName}/{YourFunctionName}";
      17. @Override
      18. public void initialize(Context context) throws IOException {
      19. FunctionComputeLogger fcLogger = context.getLogger();
      20. fcAppLoader.setFCContext(context);
      21. // Load code from OSS
      22. fcAppLoader.loadCodeFromOSS(ossEndPoint, bucket, key);
      23. // Init webapp from code
      24. fcAppLoader.initApp(userContextPath, HelloWeb.class.getClassLoader());
      25. }
      26. @Override
      27. public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
      28. throws IOException, ServletException {
      29. try {
      30. fcAppLoader.forward(request, response);
      31. } catch (Exception e) {
      32. e.printStackTrace();
      33. }
      34. }
      35. }
    • Reference the Maven repository

      1. <dependency>
      2. <groupId>com.aliyun.fc.runtime</groupId>
      3. <artifactId>fc-java-core</artifactId>
      4. <version>1.3.0</version>
      5. </dependency>
      6. <dependency>
      7. <groupId>com.aliyun.fc.runtime</groupId>
      8. <artifactId>fc-java-common</artifactId>
      9. <version>1.0.0</version>
      10. </dependency>

Java code packaging

Use Maven to package the code

  1. Add the maven-assembly-plugin plug-in to pom.xml

    1. <build>
    2. <plugins>
    3. <plugin>
    4. <artifactId>maven-assembly-plugin</artifactId>
    5. <version>3.1.0</version>
    6. <configuration>
    7. <descriptorRefs>
    8. <descriptorRef>jar-with-dependencies</descriptorRef>
    9. </descriptorRefs>
    10. <appendAssemblyId>false</appendAssemblyId> <! -- this is used for not append id to the jar name -->
    11. </configuration>
    12. <executions>
    13. <execution>
    14. <id>make-assembly</id> <! -- this is used for inheritance merges -->
    15. <phase>package</phase> <! -- bind to the packaging phase -->
    16. <goals>
    17. <goal>single</goal>
    18. </goals>
    19. </execution>
    20. </executions>
    21. </plugin>
    22. <plugin>
    23. <groupId>org.apache.maven.plugins</groupId>
    24. <artifactId>maven-compiler-plugin</artifactId>
    25. <configuration>
    26. <source>1.8</source>
    27. <target>1.8</target>
    28. </configuration>
    29. </plugin>
    30. </plugins>
    31. </build>
  2. Package the code

    1. mvn package

The JAR package is stored in the target directory.

Use Maven to package the code, and store the dependencies in the/lib directory as JAR packages.

As the dependencies of the project increase, the JAR package also becomes larger. The uploaded JAR or ZIP package is extracted and then the code in the file is loaded and executed. Therefore, the JAR package that you created in the preceding examples may contain a large number of class files. Consequently, the extraction process is time-consuming. It takes a long period of time to invoke the function for the first time.

We recommend to store the third-party dependencies in the /lib directory as JAR packages.

A solution using the maven-dependency-plugin plug-in is as follows:

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-dependency-plugin</artifactId>
  4. <executions>
  5. <execution>
  6. <id>copy-dependencies</id>
  7. <phase>prepare-package</phase>
  8. <goals>
  9. <goal>copy-dependencies</goal>
  10. </goals>
  11. <configuration>
  12. <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
  13. <includeScope>runtime</includeScope>
  14. </configuration>
  15. </execution>
  16. </executions>
  17. </plugin>

After you run mvn package, the directory of the packaged JAR file is as follows:

  1. */*.class
  2. lib/*.jar

Use IDEA to package the code

  1. Configure parameters for exporting the JAR file:

    java1

    java2

    java3

  2. Verify packaging results

    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/