https://github.com/dsyer/azure-docs
https://github.com/dsyer/azure-docs
java spring spring-boot
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/dsyer/azure-docs
- Owner: dsyer
- Created: 2018-04-18T12:50:13.000Z (about 8 years ago)
- Default Branch: main
- Last Pushed: 2020-06-15T09:34:01.000Z (about 6 years ago)
- Last Synced: 2025-06-27T02:40:12.964Z (12 months ago)
- Topics: java, spring, spring-boot
- Language: Java
- Size: 76.2 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.adoc
Awesome Lists containing this project
README
= Spring Cloud Function 2.0 and Azure Functions
https://github.com/spring-cloud/spring-cloud-function[Spring Cloud
Function] has had support for Microsoft
https://azure.microsoft.com/en-gb/services/functions[Azure Functions]
since version 1.0, but in the latest 2.0 releases (still in milestone
phase) we decided to change the programming model a bit. This article
describes what the changes mean for users, and provides a bit of
background behind the shift. We in the Spring team had a lot of fun
working on this and collaborating with the folks at Microsoft to get
the best blend of the two technologies for our users.
== Azure Functions for Java
Microsoft has had Java support in Azure Functions for a while, and it
enables developers to easily write and deploy Java code that connects
in a serverless way to a wide range of platform services (events,
databases, storage, HTTP gateways, etc.) in Azure. It comes with an
annotation-based programming model that puts the function
implementations in Java methods. So you write a method and annotation
it with `@FunctionName`, and it becomes an Azure Function. There is a
rich set of tools based on a Maven plugin (currently) that drives the
Azure command line and can be used to build a function, run and debug
it locally and deploy it to the cloud. There is a
https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven[Quickstart
Guide] on the Azure website which will help you get all the
pre-requisites installed and working, and there is more detailed
documentation about how Azure Functions works in the
https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-java[Developer's
Guide].
The annotations also tie the function method parameters and return
types to the services used at deployment time. For example, if you
want to bind to an HTTP gateway at deployment time you use
`@HttpTrigger`:
```java
@FunctionName("uppercase")
public Bar execute(
@HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST },
authLevel = AuthorizationLevel.ANONYMOUS) Foo foo,
ExecutionContext context) {
return new Bar(foo.getValue());
}
```
In this example we accept an incoming HTTP POST request and Azure
binds its body to a POJO of type `Foo`. We transform the `Foo` into a
`Bar` and it comes back to the caller in the HTTP response.
HTTP triggers are in the top 5 most popular integrations in Azure
Functions, but even more popular are the event-based and storage or
database-based triggers. The complete list can be found in the
https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings[Triggers
and Bindings] documentation - there is a table where you can click on
a specific binding or trigger and it will take you to reference page
where there are code samples in all languages, including Java.
Here's another example using the Azure Event Hub as an input and
Cosmos DB as an output. This example is
https://github.com/dsyer/azure-docs[in github]:
```java
@FunctionName("uppercase")
public Bar execute(
@EventHubTrigger(name = "data", eventHubName = "events",
connection = "TRANSACTIONS_EVENT_HUB_CONNECTION_STRING")
Foo data,
@CosmosDBOutput(name = "document", databaseName = "inventory",
collectionName = "messages",
connectionStringSetting = "PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING",
createIfNotExists = true)
OutputBinding document,
final ExecutionContext context) {
return document.setValue(new Bar(foo.getValue()));
}
```
NOTE: If the incoming JSON cannot be converted to the function input
type (`Foo` in this case) you will see Azure fail with a confusing `no
such method` error. If you see that you might be able to change the
`@FunctionName` method to a `String` input and eyeball the data to
make sure it is bindable to the desired input type.
The annotations carry connection credential information through an
indirection to environment variables that are configured in the
function deployment. The configuration for all that happens in the
build `pom.xml` through the Azure Functions Maven plugin. For example:
```xml
com.microsoft.azure
azure-functions-maven-plugin
${functionResourceGroup}
${functionAppName}
${functionAppRegion}
FUNCTIONS_EXTENSION_VERSION
beta
TRANSACTIONS_EVENT_HUB_CONNECTION_STRING
${TRANSACTIONS_EVENT_HUB_CONNECTION_STRING}
PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING
${PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING}
MSDEPLOY_RENAME_LOCKED_FILES
1
package-functions
package
```
In this case the environment variable names link the plugin
configuration to the function binding declaration. For instance the
`@EventHubTrigger` has a `connection` attribute that will be
popeulated at runtime from the
`TRANSACTIONS_EVENT_HUB_CONNECTION_STRING` environment variable. The
plugin configures it remotely using a local environment variable with
the same name (notice the `${}` placeholders), which the developer or
CI process is responsible for setting up at runtime.
Your own personal connection strings are secrets and can be found in
the https://portal.azure.com[Azure Dashboard] - when you click on the
relevant resource there is usually a `Connection Strings` link (or
similar) that you can copy and paste to your local process (e.g. in a
script that you run locally but do not check into source
control). E.g. you might use a `setup-env.sh` script like this:
```
export PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING="AccountEndpoint=https://..."
export TRANSACTIONS_EVENT_HUB_CONNECTION_STRING="Endpoint=sb://..."
```
and source it once at the beginning of a terminal session.
There are some other plugin declarations in the `pom.xml` of the
sample. They are all important but basically boilerplate - you should
be able to copy them and re-use the same configuration in all Azure
Function Applications.
== Spring Cloud Function
Spring Cloud Function aims to support similar serverless use cases
when the application developer declares Spring beans of type
`java.util.Function`. The advantages of using Spring Cloud Function on
Azure, as opposed to vanilla Java functions, are that the actual
business logic code is (in principle) portable to other platforms, and
it is a familiar programming model for existing Spring users. Also,
all the usual benefits of Spring apply: dependency injection and
comprehensive integration with many other Java libraries.
The equivalent of both the examples above would be a single `@Bean`:
```java
@Bean
public Function uppercase() {
return foo -> new Bar(foo.getValue().toUpperCase());
}
```
In version 1.0 of Spring Cloud Function, the user had to map the
Microsoft annotations manually to a JSON deployment descriptor, and
wrap it up manually into an archive with the right layout for the
platform. The process was brittle (but independent of the Azure Java
programming model).
In version 2.0 this would still work, but we have chosen to support
the use of the Azure annotations a bit more explicitly. So now we have
a base class that application developers can extend and decorate with
the Azure annotations. The example above would be exactly the same
`@Bean` and one of the `execute` methods above would be inserted into
the subclass of the Spring Cloud handler. Example:
```java
public class UppercaseHandler extends AzureSpringBootRequestHandler {
@FunctionName("uppercase")
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) Foo foo,
ExecutionContext context) {
return super.handle(foo, context);
}
```
Notice that the base class `AzureSpringBootRequestHandler` is generic
with type parameters for input and output. You have to match the input
type to the incoming event data, which will be presented in JSON and
converted using Jackson by Azure before Spring has anything to
do. There are 2 utility methods in the base class, one (`handle`)
which returns the response object, and one (`handleOutput`) which
accepts an `OutputBinding` and binds it to the output from the user
`Function`.
NOTE: The base class is pure boilerplate, and serves only as
an external representation of the binding of your Spring functions
to the serverless platform services. The Azure bindings would be ignored
if you were running in a different platform, or locally via the
Spring Cloud Function web adapter, for instance. It might be possible
in the future to replace it with an interface declaration - the
Azure platform doesn't permit this currently, but it's something we
are looking at with the Microsoft team.
There are various configuration options that drive the runtime
behaviour of the Azure Function. The most important (and only
mandatory) one is the `MAIN_CLASS`, which is the main
`@SpringBootApplication` class that carries the declaration of the
`Function` (or `Functions`). You can specify this as an environment
variable, or as the `Main-Class` entry in the application jar
manifest. As long as your app has a main class with precisely one
function, there is no need to do anything else. In the sample app we
use the manifest to define the main class:
```xml
org.apache.maven.plugins
maven-jar-plugin
example.FunctionApplication
```
If your app has multiple `Function` beans, they can be mapped to the
Azure function though the `@FunctionName` annotation - the bean name
(or more precisely the name i nthe `FunctionCatalog`) matches the
function name. In this way you can create an Azure Function
Application, which is a single deployment artifact for a group of
functions. If you prefer, you can also use an arbitrary
`@FunctionName` and configure the Spring Cloud Function name through
an environment variable `FUNCTION_NAME` or a `function.name` in your
`application.properties`.
There is another simple sample of how to set up a Spring Cloud
Function as an Azure Function in
https://github.com/spring-cloud/spring-cloud-function/blob/master/spring-cloud-function-samples/function-sample-azure/README.adoc[the
project repo] - this one is an HTTP trigger from an Azure perspective,
but the Spring Cloud Function parts are very similar.
NOTE: If you are at https://springoneplatform.io[Spring One Platform] this week, come along to a https://springoneplatform.io/2018/sessions/running-serverless-applications-using-spring-and-microsoft-azure[presentation on Spring and Azure Functions] by Jeff Hollan (Microsoft) and Oleg Zhurakousky (Pivotal).