Spring Web
Spring 5.0 introduced compatibility with Reactive Streams, a library interoperability standardization effort co-lead by Lightbend (with Akka Streams) along with Kaazing, Netflix, Pivotal, Red Hat, Twitter and many others.
Thanks to adopting Reactive Streams, multiple libraries can now inter-op since the same interfaces are implemented by all these libraries. Akka Streams by-design, hides the raw reactive-streams types from end-users, since it allows for detaching these types from RS and allows for a painless migration to java.util.concurrent.Flow
which was introduced in Java 9.
This Alpakka module makes it possible to directly return a Source
in your Spring Web endpoints.
Project Info: Alpakka Spring Web | |
---|---|
Artifact | com.lightbend.akka
akka-stream-alpakka-spring-web
9.0.0
|
JDK versions | Eclipse Temurin JDK 11 Eclipse Temurin JDK 17 |
Scala versions | 2.13.12 |
JPMS module name | akka.stream.alpakka.spring.web |
License | |
Readiness level |
Since 0.14, 2017-10-14
|
Home page | https://doc.akka.io/libraries/alpakka/current |
API documentation | |
Forums | |
Release notes | GitHub releases |
Issues | Github issues |
Sources | https://github.com/akka/alpakka |
Artifacts
The Akka dependencies are available from Akka’s library repository. To access them there, you need to configure the URL for this repository.
- sbt
resolvers += "Akka library repository".at("https://repo.akka.io/maven")
- Maven
<project> ... <repositories> <repository> <id>akka-repository</id> <name>Akka library repository</name> <url>https://repo.akka.io/maven</url> </repository> </repositories> </project>
- Gradle
repositories { mavenCentral() maven { url "https://repo.akka.io/maven" } }
Additionally, add the dependencies as below.
- sbt
val AkkaVersion = "2.10.0" libraryDependencies ++= Seq( "com.lightbend.akka" %% "akka-stream-alpakka-spring-web" % "9.0.0", "com.typesafe.akka" %% "akka-stream" % AkkaVersion )
- Maven
<properties> <akka.version>2.10.0</akka.version> <scala.binary.version>2.13</scala.binary.version> </properties> <dependencies> <dependency> <groupId>com.lightbend.akka</groupId> <artifactId>akka-stream-alpakka-spring-web_${scala.binary.version}</artifactId> <version>9.0.0</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-stream_${scala.binary.version}</artifactId> <version>${akka.version}</version> </dependency> </dependencies>
- Gradle
def versions = [ AkkaVersion: "2.10.0", ScalaBinary: "2.13" ] dependencies { implementation "com.lightbend.akka:akka-stream-alpakka-spring-web_${versions.ScalaBinary}:9.0.0" implementation "com.typesafe.akka:akka-stream_${versions.ScalaBinary}:${versions.AkkaVersion}" }
The table below shows direct dependencies of this module and the second tab shows all libraries it depends on transitively.
- Direct dependencies
Organization Artifact Version com.typesafe.akka akka-stream_2.13 2.10.0 org.scala-lang scala-library 2.13.12 org.springframework.boot spring-boot-autoconfigure 2.7.18 org.springframework spring-context 5.3.39 org.springframework spring-core 5.3.39 - Dependency tree
com.typesafe.akka akka-stream_2.13 2.10.0 BUSL-1.1 com.typesafe.akka akka-actor_2.13 2.10.0 BUSL-1.1 com.typesafe config 1.4.3 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 com.typesafe.akka akka-protobuf-v3_2.13 2.10.0 BUSL-1.1 org.reactivestreams reactive-streams 1.0.4 MIT-0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.scala-lang scala-library 2.13.12 Apache-2.0 org.springframework.boot spring-boot-autoconfigure 2.7.18 Apache License, Version 2.0 org.springframework.boot spring-boot 2.7.18 Apache License, Version 2.0 org.springframework spring-context 5.3.39 Apache License, Version 2.0 org.springframework spring-aop 5.3.39 Apache License, Version 2.0 org.springframework spring-beans 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-beans 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-expression 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-context 5.3.39 Apache License, Version 2.0 org.springframework spring-aop 5.3.39 Apache License, Version 2.0 org.springframework spring-beans 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-beans 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-expression 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0 org.springframework spring-core 5.3.39 Apache License, Version 2.0 org.springframework spring-jcl 5.3.39 Apache License, Version 2.0
Usage
Using Akka Streams in Spring Web (or Boot for that matter) is very simple, as Alpakka provides autoconfiguration to the framework, which means that Spring is made aware of Sources and Sinks etc.
All you need to do is include the above dependency (akka-stream-alpakka-spring-web
), start your app as usual:
- Java
-
source
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
And you’ll be able to return Akka Streams in HTTP endpoints directly:
- Java
-
source
import javax.annotation.PostConstruct; import akka.NotUsed; import akka.actor.ActorSystem; import akka.event.LoggingAdapter; import akka.stream.javadsl.Source; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.util.Assert; @RestController public class SampleController { @Value("${akka.stream.alpakka.spring.web.actor-system-name}") private String actorSystemName; @Autowired private ActorSystem system; @RequestMapping("/") public Source<String, NotUsed> index() { return Source.repeat("Hello world!").intersperse("\n").take(10); } @PostConstruct public void setup() { LoggingAdapter log = system.log(); log.info("Injected ActorSystem Name -> {}", system.name()); log.info("Property ActorSystemName -> {}", actorSystemName); Assert.isTrue((system.name().equals(actorSystemName)), "Validating ActorSystem name"); } }
Both javadsl
and scaladsl
Akka Stream types are supported.
In fact, since Akka supports Java 9 and the java.util.concurrent.Flow.*
types already, before Spring, you could use it to adapt those types in your applications as well.
The provided configuration
The automatically enabled configuration is as follows:
- Java
-
source
import akka.actor.ActorSystem; @Configuration @ConditionalOnClass(akka.stream.javadsl.Source.class) @EnableConfigurationProperties(SpringWebAkkaStreamsProperties.class) public class SpringWebAkkaStreamsConfiguration { private static final String DEFAULT_ACTORY_SYSTEM_NAME = "SpringWebAkkaStreamsSystem"; private final ActorSystem system; private final SpringWebAkkaStreamsProperties properties; public SpringWebAkkaStreamsConfiguration(final SpringWebAkkaStreamsProperties properties) { this.properties = properties; final ReactiveAdapterRegistry registry = ReactiveAdapterRegistry.getSharedInstance(); system = ActorSystem.create(getActorSystemName(properties)); new AkkaStreamsRegistrar(system).registerAdapters(registry); } @Bean @ConditionalOnMissingBean(ActorSystem.class) public ActorSystem getActorSystem() { return system; } public SpringWebAkkaStreamsProperties getProperties() { return properties; } private String getActorSystemName(final SpringWebAkkaStreamsProperties properties) { Objects.requireNonNull( properties, String.format( "%s is not present in application context", SpringWebAkkaStreamsProperties.class.getSimpleName())); if (isBlank(properties.getActorSystemName())) { return DEFAULT_ACTORY_SYSTEM_NAME; } return properties.getActorSystemName(); } private boolean isBlank(String str) { return (str == null || str.isEmpty()); } }
In case you’d like to manually configure it slightly differently.
Shameless plug: Akka HTTP
While the integration presented here works, it’s not quite the optimal way of using Akka in conjunction with serving HTTP apps. If you’re new to reactive systems and picking technologies, you may want to have a look at Akka HTTP.
If, for some reason, you decided use Spring MVC this integration should help you achieve the basic streaming scenarios though.