Developing with Java or Scala
Select your preferred language (Java/Scala) above.
The Akka Serverless Java Scala SDK guides you through implementing components matching the protobuf APIs you design. This page describes prerequisites for Java Scala development and basic requirements for a development project.
Lightbend provides Tier 1 support for the Java Scala SDK. See an explanation of support tiers for more information. |
Your development project needs to include the Akka Serverless Java Scala SDK and logic to start the gRPC server. You define your components in gRPC descriptors and use protoc
to compile them. Finally, you implement business logic for service components.
To save the work of starting from scratch, the Java code generation tool creates a project from a template, complete with descriptors and implementations. Or, you can start from one of our fully implemented Quickstart applications.
Prerequisites
The following are required to develop services in Java:
- Java
-
Akka Serverless requires Java 11 or later.
- Apache Maven
-
For Java-based services, Akka Serverless relies on Apache Maven
as build tool. The Akka Serverless Maven plugin creates initial Java code for your components and the required surrounding code.
- sbt
-
For Scala-based services, Akka Serverless relies on sbt
as build tool. The Akka Serverless sbt plugin creates initial Scala code for your components and the required surrounding code.
- Docker
-
Akka Serverless requires Docker
20.10.8 for building your service images. Most popular build tools have plugins that assist in building Docker images.
Reference the Akka Serverless SDK
The following examples show how to install the SDK to build your services with Maven. The code generation tools include an Akka Serverless project template that generates the recommended project structure, including a .pom
file build.sbt with the necessary references.
In your .pom
file build.sbt, add the following:
- Java
-
<dependencies> <dependency> <groupId>com.akkaserverless</groupId> <artifactId>akkaserverless-java-sdk</artifactId> <version>0.10.6</version> </dependency> <dependency> <groupId>com.akkaserverless</groupId> <artifactId>akkaserverless-java-sdk-testkit</artifactId> <version>0.10.6</version> <scope>test</scope> </dependency> </dependencies>
- Scala
-
scalaVersion := "2.13.6" enablePlugins(AkkaserverlessPlugin)
And in project/plugins.sbt
:
addSbtPlugin("com.akkaserverless" % "sbt-akkaserverless" % "0.10.6")
Configure JSON formatted logging
Akka Serverless supports JSON formatted logging to provide multi-line messages formatted in JSON syntax. Always use JSON formatted logging for your Akka Serverless projects to efficiently analyze and easily leverage logging information.
Build and deploy the Quickstart example to see JSON formatted logging in action. |
JSON formatted logging is enabled by default in the projects created by the Akka Serverless project template. It includes a transitive dependency on logback-json-classic
and a logback.xml
file as shown here:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{ISO8601} %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="JSON-STDOUT" target="System.out" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="com.akkaserverless.javasdk.logging.LogbackJsonLayout">
<timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
<timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>
<appendLineSeparator>true</appendLineSeparator>
<jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
<prettyPrint>false</prettyPrint>
</jsonFormatter>
</layout>
</encoder>
</appender>
<appender name="ASYNC-JSON-STDOUT" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>8192</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="JSON-STDOUT"/>
</appender>
<logger name="akka" level="INFO"/>
<logger name="com.akkaserverless" level="INFO"/>
<logger name="akka.http" level="INFO"/>
<logger name="io.grpc" level="INFO"/>
<root level="INFO">
<!-- <appender-ref ref="STDOUT"/>-->
<appender-ref ref="ASYNC-JSON-STDOUT"/>
</root>
</configuration>
In the logback.xml
you may want to adjust the log level for different loggers (typically a package or class name).
For local development you can switch to the STDOUT
appender to make the logs more readable, or use <prettyPrint>true</prettyPrint>
in the jsonFormatter
. Don’t use prettyPrint
in production since the logging infrastructure will not handle multi-line log messages.
There is a separate src/test/resources/logback-test.xml that is used when running tests.
|
Create a main class
The Akka Serverless plugin will create a main class for you and make sure all components get registered with the Akka Serverless server. The following code snippet shows an example that registers an Event Sourced Entity and starts the server:
- Java
-
package com.example.shoppingcart; import com.akkaserverless.javasdk.AkkaServerless; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.example.shoppingcart.domain.ShoppingCart; import com.example.shoppingcart.view.ShoppingCartViewServiceImpl; public final class Main { private static final Logger LOG = LoggerFactory.getLogger(Main.class); public static AkkaServerless createAkkaServerless() { // The AkkaServerlessFactory automatically registers any generated Actions, Views or Entities, // and is kept up-to-date with any changes in your protobuf definitions. // If you prefer, you may remove this and manually register these components in a // `new AkkaServerless()` instance. return AkkaServerlessFactory.withComponents( ShoppingCart::new, ShoppingCartViewServiceImpl::new ); } public static void main(String[] args) throws Exception { LOG.info("starting the Akka Serverless service"); createAkkaServerless().start(); } }
- Scala
-
package customer import com.akkaserverless.scalasdk.AkkaServerless import customer.action.CustomerActionImpl import customer.domain.CustomerValueEntity import customer.view.CustomerByEmailView import customer.view.CustomerByNameView import customer.view.CustomerSummaryByNameView import customer.view.CustomersResponseByNameView import org.slf4j.LoggerFactory object Main { private val log = LoggerFactory.getLogger("customer.Main") def createAkkaServerless(): AkkaServerless = { // The AkkaServerlessFactory automatically registers any generated Actions, Views or Entities, // and is kept up-to-date with any changes in your protobuf definitions. // If you prefer, you may remove this and manually register these components in a // `AkkaServerless()` instance. AkkaServerlessFactory.withComponents( new CustomerValueEntity(_), new CustomerActionImpl(_), new CustomerByEmailView(_), new CustomerByNameView(_), new CustomerSummaryByNameView(_), new CustomersResponseByNameView(_)) /* return AkkaServerlessFactory.withComponents( new CustomerValueEntity(_), new CustomerByNameView(_)) */ } def main(args: Array[String]): Unit = { log.info("starting the Akka Serverless service") createAkkaServerless().start() } }