Spring Web

Spring 5.0 introduced compatibility with Reactive Streams, a library interoperability standardization effort co-lead by Lightbend (with Apache Pekko Streams and 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. Apache Pekko 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 Apache Pekko Connectors module makes it possible to directly return a Source in your Spring Web endpoints.

Project Info: Apache Pekko Connectors Spring Web
Artifact
org.apache.pekko
pekko-connectors-spring-web
1.0.2
JDK versions
OpenJDK 8
OpenJDK 11
OpenJDK 17
Scala versions2.13.14, 2.12.20, 3.3.3
JPMS module namepekko.stream.connectors.spring.web
License
API documentation
Forums
Release notesGitHub releases
IssuesGithub issues
Sourceshttps://github.com/apache/pekko-connectors

Artifacts

sbt
val PekkoVersion = "1.0.3"
libraryDependencies ++= Seq(
  "org.apache.pekko" %% "pekko-connectors-spring-web" % "1.0.2",
  "org.apache.pekko" %% "pekko-stream" % PekkoVersion
)
Maven
<properties>
  <pekko.version>1.0.3</pekko.version>
  <scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencies>
  <dependency>
    <groupId>org.apache.pekko</groupId>
    <artifactId>pekko-connectors-spring-web_${scala.binary.version}</artifactId>
    <version>1.0.2</version>
  </dependency>
  <dependency>
    <groupId>org.apache.pekko</groupId>
    <artifactId>pekko-stream_${scala.binary.version}</artifactId>
    <version>${pekko.version}</version>
  </dependency>
</dependencies>
Gradle
def versions = [
  PekkoVersion: "1.0.3",
  ScalaBinary: "2.13"
]
dependencies {
  implementation "org.apache.pekko:pekko-connectors-spring-web_${versions.ScalaBinary}:1.0.2"
  implementation "org.apache.pekko:pekko-stream_${versions.ScalaBinary}:${versions.PekkoVersion}"
}

The table below shows direct dependencies of this module and the second tab shows all libraries it depends on transitively.

Usage

Using Apache Pekko Streams in Spring Web (or Boot for that matter) is very simple, as Apache Pekko Connectors 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 (pekko-connectors-spring-web), start your app as usual:

Java
sourceimport 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 Apache Pekko Streams in HTTP endpoints directly:

Java
sourceimport javax.annotation.PostConstruct;

import org.apache.pekko.NotUsed;
import org.apache.pekko.actor.ActorSystem;
import org.apache.pekko.event.LoggingAdapter;
import org.apache.pekko.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("${org.apache.pekko.stream.connectors.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 Apache Pekko Stream types are supported.

In fact, since Apache Pekko 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 org.apache.pekko.actor.ActorSystem; @Configuration @ConditionalOnClass(org.apache.pekko.stream.javadsl.Source.class) @EnableConfigurationProperties(SpringWebPekkoStreamsProperties.class) public class SpringWebPekkoStreamsConfiguration { private static final String DEFAULT_FACTORY_SYSTEM_NAME = "Pekko SpringWebPekkoStreamsSystem"; private final ActorSystem system; private final SpringWebPekkoStreamsProperties properties; public SpringWebPekkoStreamsConfiguration(final SpringWebPekkoStreamsProperties properties) { this.properties = properties; final ReactiveAdapterRegistry registry = ReactiveAdapterRegistry.getSharedInstance(); system = ActorSystem.create(getActorSystemName(properties)); new PekkoStreamsRegistrar(system).registerAdapters(registry); } @Bean @ConditionalOnMissingBean(ActorSystem.class) public ActorSystem getActorSystem() { return system; } public SpringWebPekkoStreamsProperties getProperties() { return properties; } private String getActorSystemName(final SpringWebPekkoStreamsProperties properties) { Objects.requireNonNull( properties, String.format( "%s is not present in application context", SpringWebPekkoStreamsProperties.class.getSimpleName())); if (isBlank(properties.getActorSystemName())) { return DEFAULT_FACTORY_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: Apache Pekko HTTP

While the integration presented here works, it’s not quite the optimal way of using Apache Pekko in conjunction with serving HTTP apps. If you’re new to reactive systems and picking technologies, you may want to have a look at Apache Pekko HTTP.

If, for some reason, you decided use Spring MVC this integration should help you achieve the basic streaming scenarios though.