GUILLAUME LAFORGE:
Hello, everyone, and welcome to this session
about the new Java 11 runtime for Cloud functions. Java is a very important
and widely used programming language
in the enterprise. And customers have
asked for Java support ever since we released the
first runtime for Google Cloud Functions. So let's dive into Java
11 for Cloud functions. And that's my pleasure
to introduce you to my colleague Eamonn. EAMONN MCMANUS: Hi,
I'm Eamonn McManus. I'm the lead developer
for GCF Java. GUILLAUME LAFORGE: And
I'm Guillaume Laforge. I'm a Developer Advocate
for Google Cloud. And I'm focusing on our
serverless solutions. I also contributed to the
Java API for this runtime. So I'm very excited to
share that with you. So let's start with a few words
about the serverless concept. More than just a
buzzword, serverless is both about an operational
and a programming perspective. From an operational
standpoint, developers can focus on their
code, and don't need to bother about servers to
manage, clusters to provision. It's a pay for usage model. So you pay proportionately
to the number of times your functions are
invoked or the duration. So you really pay only for
the underlying infrastructure when it's actually used for your
workloads, not when it's idle. For the programming
model, developers are encouraged to write more
granular services instead of the good old big monolith. And functions react to events,
so whether it's an http call or it's some event coming from
your Cloud infrastructure. Furthermore, we've been
building Cloud Functions with an open approach. So we'll tell you more about
this with the Functions framework. And you can easily run
your functions elsewhere, not just in the Cloud, but also
on your local machine, which improves the developer
experience, as well as anywhere else, on premises, or even
in other clouds, potentially. So Google Cloud offers three
serverless compute solutions. So there's Cloud
Functions, which is the topic of the day, where
you write event-driven services a small unit of code. There's App Engine
for deploying your web application, your services,
your backend APIs, like mobile backends. And there's Cloud Run, where
you can deploy anything within a container
with any language that you want any runtime, any
executable you want to use. Now, zooming back on
to Cloud Functions, there were so far only
three runtimes available. So there's node
js, Python, and Go. And today, we're also happy
to have Java 11, which is available in beta. Let's now have a look at the
types and shape of functions. And I'll let Eamonn tell you
all about our Java function API. EAMONN MCMANUS:
Thanks, Guillaume. So there's basically
two kinds of functions. And this is true for all
of the different language runtimes on GCF. There are http functions
and background functions. So http functions react
to a URL being accessed. So it's a public URL
subject to access controls. And whenever there's an http
request made to that URL, the function gets executed. And it can specify what the
reply to the http request is going to be. And then there's
background functions. And those are invoked by
the system in response to certain events. And so we see here some of
the events that that might be. For example, Pub/Sub
events or a file gets created in Cloud
storage, and so on. So, Java doesn't really have
a notion of functions as such. So the approach that we
chose was a familiar one for Java, which is to
define an interface that has a single method. And then your function
is an implementation of that interface. So it has that method in it. So when we look
at http functions, the interface in question
is called http function. Typically, you would
just type something like, in your IDE class example,
implements http function. And then you would ask,
basically get the IDE to fill in the details. It knows that that interface
has one method so it provides that method for you. You don't have to remember
the method signature. And then all you need to do
is implement that method. And it's unsurprising. There is a request
parameter that allows you to see the details
of the incoming http request, like what the URL was, the query
parameters, if there's a body and what that was. And then there's a
response parameter that allows you to say what
the http response is going to look like, status code, the
content type, the body of that, and so on. GUILLAUME LAFORGE:
Let's have a look at a slightly more complex
function, an http function. So I'm defining a new
class in a package. I'm importing the key
functions framework APIs, the http function
interface, the http request and response. And in this example, we're going
to check whether a number is prime or not. So we're going to use a
[INAUDIBLE] dependency. Here, we're going to use apache
commons math, particularly the prime's class, which
gives us the ability to know if a number is prime or not. So, let's implement the
http function interface and overwrite the
service method. The service method takes an http
request and an http response. Here you can see on
the response object. I can, for example, set
the status code 200, set the content type. Here, it's just some plain text. And I can also get the writer
to write on the output. On the request, on
the request object, I can call get first
query parameter to get the query parameters. In this case, that's the number
that is passed as a parameter. If there's no number, you
don't necessarily know. So this method actually
returns an optional. So if there's a number
that is present, then I can have some logic. And otherwise, I'm going to say,
OK, please provide a number. So if a number is provided, I'm
going to look at this number. It's actually a string. It's part of the query string. So I'm going to turn that string
into an integer in the end value variable. And then I'm going to say, OK,
is this value a prime number? And then I call the dependency
from the primes class. Primes is prime with the values. It's going to return a Boolean
value, whether it's prime or not. And if there was a parsing
error from the query string, I'm going to write, please
provide a valid number. And let's have a look
at the [INAUDIBLE].. Here I'm building with Maven. So I'm saying, OK,
I'm using Java 11. And here, you can see
the two dependencies. The dependency on the
function's framework API with the provided scope,
because the environment on the Cloud Functions
runtime provides this API. And I have my user dependency
on apache commons math. And now let's have a
look at how to run this. So please provide a number. If I don't provide any number. So let's add a number here. ABC. Oh. Please provide valid number. So let's do it again,
but with 1, 2, 3, 4. So is this number prime? It's false. So let's say, let's try
it with another number. 17. Is 17 prime? Yes, that's true. So here's our first
http function. EAMONN MCMANUS: So we
saw http functions. What about background functions? The way the background
functions work behind the scenes is that you still
have incoming http, but you don't have to be
concerned with it anymore. So the http has a payload,
which is a JSON payload. And we can consider
that comes in two parts. There is essentially
an envelope, which is the things that are
common to all kinds of events. And that says what the event
type is, what the timestamp is, and so on. And then there's
the content, which is the things that are specific
to the particular event that you're receiving. Then there are two
ways of handling these. They're quite similar. They just have to do with how
the JSON is presented to you. So in both cases, the envelope
will be parsed for you. You don't have to see how
that's represented in JSON. That's the second parameter
to these functions. The first parameter, then,
is where they differ. In the background function case,
the interface call background function, that parameter will be
deserialized into a Java class that you provide using
the JSON framework. So that makes it a
little more convenient to get out the
contents of the JSON. And then in the
second form, we just give you a string, which
is the incoming JSON as is. And then you can parse that,
using whatever framework you like, Jackson or whatever. So we've seen how
to write functions. Now, Guillaume will talk about
how you build and deploy them. GUILLAUME LAFORGE: So let's
see how we can do that. There are a couple of options
for building functions. Your functions can
be built in the Cloud from sources using Maven
or Gradle build tools. Your sources should provide a
pom.xml file or build.gradle project file. You can also build a JAR with
any build tool that you want. Either a shaded JAR
with dependencies within the JAR file. Or JAR archive whose manifest
descriptor provides class path attribute pointing at
the JAR dependencies in some local subdirectory. With Maven, to build a
JAR project containing your functions,
your pom.xml project build file must import the
function's framework API dependency. This is actually a
dependency, which is available on Maven
Central or [INAUDIBLE].. It's a JAR that provides
various interfaces we've seen representing functions,
requests, responses, context, et cetera. If you want to build with
Gradle, similarly to Maven, you need to have a build.gradle
file with a function's framework API
dependency as well. So here, the dependency
is played over two lines, but it's really just
for readability purpose. And that's all. When you deploy this
project on Cloud Functions, the platform will take
care of the build for you. You can then deploy
your functions from either the Google
Cloud console UI, from the G Cloud command line,
or with the Maven function plug-in. We provide a dedicated
plug-in for that. In the G Cloud command here,
notice the Java 11 runtime flag, which proves that we're
indeed using this new runtime. Also note the entry point. It corresponds to the
fully qualified class name of your Java function. Now that we've seen what
functions look like, I'll let Eamonn tell you more
about the developer experience. EAMONN MCMANUS: So,
in common with all of the other runtimes
on GCF, we have a notion of a functions framework. And that is basically that the
code that we-- the framework that we use to run your function
when you deploy it to GCF is also available as an open
source project on GitHub. You can download
that and build it, and you can run your function,
of course, by deploying it. But you can also run it
locally on your machine using this functions framework. So and you can also use
that to package the function into a container and
deploy that container wherever you like to execute
the function wherever you like. So what this looks like
in Maven, for example, is that in your
pom.xml, we supply you with a plug-in that makes
this a little bit easier that is based on top of the
function's framework. If you put this extract
of code into your pom.xml, then you can just type
on the command line, maven function code on run. We already saw this
plug-in in action to deploy the function with
maven function code and deploy. Here you can use maven
function code on run. And then you can interact
with your function, which again, is just http. You can interact with it, you
know, either from your browser or from the command line
using curl or from tests or whatever you like. GUILLAUME LAFORGE:
Let's come back to our prime number
function, which allowed us to know whether
a number was prime or not. I define the build file for
Maven, the pom.xml file. And there's a step that I
skipped, I didn't explain. That's this part. So this is where we are
actually configuring the function maven plug-in, OK? We're defining a parameter
for this plug-in. say, the function target. That's the function we want
to run with the function maven plug-in. That's this prime
number function from my com xfm package. And if I go into the terminal
and run MVN function run, it's going to run my function
locally on my machine. And it's already
running locally. And I can, again, for example,
I can do curl request locally. Here, 19 is a prime number. 1, 2, 3, 4 is not
a prime number, OK? So it's very simple. Just define the maven function
plug-in configuration here in your pom.xml file. And you're able to read
your function locally in your terminal on your
laptop, on your desktop, without having to
deploy in the Cloud. Actually, we've been
talking about Java so far. But you're not limited to
just the Java language. You can also run and use
alternative JVM languages for authoring your functions. For instance, you can use Apache
Groovy, Kotlin, [INAUDIBLE] or [INAUDIBLE]. Thanks to Java, thanks to
its Java virtual machine, Java is actually
a platform where you can run alternative
languages as well. And you can do that with Cloud
Functions for Java as well. So let's take an example. Here is an http function
example using the Apache Groovy programming language. It looks pretty similar to
our Java example from earlier. Same approach-- just implement
the http function interface and use the http request,
the http response parameters, to inspect incoming
request and reply back to the calling client. That's also the same approach
with background functions. When you implement the
background function or the raw background
function interfaces. So let's see a concrete
example with a demo. Let's have a look at
a Groovy function. It's a useful
function this time, not a hello world,
which is going to parse a file using the Ascii
doctor format, the file that is hosted on GitHub, and
which lists the official Java champions. So it's a table
with different lines and showing the pictures,
details, names, et cetera, town, country. This file is using
the Ascii doctor format, which is format-- text format--
similar to mark down. Each row for each champion
looks something like this. You've got some links. You've got, again,
country, year, et cetera. And the goal of my function
is to output something that is easier to parse for tools. And I'm going to output
JSON list of documents. So I want to transform
that into this, basically. So let's have a
look at the code. So here's my Groovy function. I'm implementing the http
function interface, as usual. I have a service method with a
request and a response object. I'm doing things like adding
a header for cache control, setting the content type. And then I'm going to
output some JSON data. I also have a look at the path,
because I can sort my Java champions by year, by country. And what's interesting as
well-- look at this and that, same thing below. We're using the
Groovy equivalent of Java lambda expressions. That's Groovy closures. So here, we are grouping
by date, sorting by key. That's the name, the country,
and again, the key here. So this is Groovy
notation, basically, right? And what else? Easily, I can fetch the document
that I'm going to parse. And then I'm using the
Ascii doctor j library to parse the document. And I go through the
various blocks of text to create champions,
instances of champions, which have a name, Twitter
alias, town, country, et cetera. So how do I do that? So let's have a look
at my pom.xml file. This time, I add a
new plug-in, that's the G Maven plus plug-in, which
is used to compile Groovy code. You have to instruct
your Maven build to say, OK, you also want to compile
some Groovy code along with Java code potentially. So that's the first plug-in. The other plug-in, that's the
Google Cloud Functions Maven plug-in. And I'm saying, OK, this
is the function to run, if I want to run the
function locally. Let's have a look at
the dependencies now. Still, the functions
framework API, which is a provided dependency. But, since I'm using
the Groovy language, I'm adding the
Groovy library here. And I also add the
Ascii doctor j library for parsing the document. What's interesting
with this function is that actually, this is a
Groovy function using some Java libraries, but also Ascii
doctor j, which is actually a ruby library, which is
interpreted with the J ruby alternative JVM language. So you have basically
three languages. Java, Groovy, Ruby at
the same time running with Cloud Functions for Java. So let's continue on
this polyglot journey with another language here. Again, that's the same
thing, but this time, we're using the Kotlin
programming language. That's pretty similar. You have to implement the
http function interface, use the http request
and response object. That's pretty much
the same thing, except, of course, that
the syntax of the language is slightly different. Alternative languages. Check. But you're not locked to the
function's framework API. It's also possible to use
familiar frameworks like Spring Cloud, Micronaut, Quarkus,
using their own programming models to create
functions for the Java 11 runtime for Cloud Functions. So let's have a look. Spring Cloud and Spring Boot
have a different approach to creating functions. In Spring, a function
is a Spring [INAUDIBLE] that returns Java
function interface, which is parameterized by an
input type and output type. Your Spring functions returns
a lambda expression, hence the arrow that you see
here, this example. But you don't use the Functions
framework API directly. You use Spring's
programming model instead. In other framework,
this time, Micronaut. For http functions,
the Micronaut framework actually uses its own annotation
driven programming model. So you can see here, we
are defining a controller, a path, path variables, et
cetera, reusing the annotations provided by the
Micronaut framework. This is really just a
plain Micronaut controller. But the Micronaut team provided
a specific Cloud Functions integration that wraps the
Functions framework interfaces. So Micronaut
developers just prefer normal a plain, usual
Micronaut controller using their programming
model that they are used to, which is pretty poor table. Because this controller can
run elsewhere in a container, as a web application, and
not just as a Cloud Function. Let's have a look at
a concrete example with the Micronaut's framework. So what does a Micronaut
function look like? I'm actually going
to use a project called Micronaut
Launch, which has been created by the
Micronaut team to scaffold a new project, a template
for your project. So you can select what
you want to create, which language you want
to use, which build, which kind of testing tool. And you can also add features. So I already added it initially. There's a specific feature
for Google Cloud Function. So the Micronaut team
created an integration for Cloud Functions Java 11. So you can click the Generate
button to generate an archive zip file for your project. But you can also click
the little Preview button to see what's generated. A controller. There's even a
Docker file if you run that, if you want
to run that function, that application, that
Micronaut application elsewhere, for example, as a
Cloud Run container. That's possible. And there's also a build. But I've already
downloaded this. And, so I have a build.gradle
file that's been generated using the function's
framework API, the invoker-- that's what allows you to run
functions locally or invoke your functions anywhere. And what's interesting
is that there's a special task that's
been added here, Run Function, which does the
same job as the Maven function plug in, which is
using the invoker to run the function locally. And it's going to call the
integration point created by the Micronaut folks,
the http function, which is going to delegate the
work to the Halo controller. So this controller, it's a
standard Micronaut controller, using the Add
Controller annotation, looking at the /halo sub path. It's going to output
some plaintext. Let's write something. GCF Java 11 rocks. Let's save this. And then let's run that locally. So it's going to build this
function locally and run it locally using the
functions invoker through the Gradle build. So let's have a look. Yeah. GCF Java 11 rocks. So, unlike Spring
Cloud and Micronaut, Quarkus follows the function
framework native API approach, just decorating functions with
Quarkus specific annotations, like @Named,
@ApplicationScoped, or @Inject to do dependency injection
for the dependencies that are needed for your function. This is also the same approach
for background functions. So taking advantage of
Quarkus annotations, but following the
Functions framework API using the
Functions framework API interfaces instead. So that's about it. I'll let Eamonn conclude. EAMONN MCMANUS: So, we saw
a rapid tour of GCF Java. So Java is one of the new
runtimes available with GCF now. We saw that there are two kinds
of functions, http functions and background functions. Both functions are
portable, thanks to the Functions framework. So you can deploy them using
the Functions framework in production to GCF. But you can also
run them locally. And you can put
them in a container and deploy them
anywhere you want. We saw all of that it isn't
really just a Java runtime. It's the JVM runtime. So you can run any JVM language,
such as Kotlin or Groovy. And finally, we saw that it
works not only on its own, but also in conjunction
with a certain number of other frameworks, so such
as Spring Cloud, Quarkus, and Micronaut. So that's GCF Java. And we're excited to see
what you build with it.