リアルタイム更新の実装
Spring BootでSubscription Resolverを開発し、イベントを公開してクライアントにライブデータを送信します。
「リアルタイム更新の実装」はCoddyKit上の無料GraphQL APIs with Spring Bootレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGraphQL APIs with Spring Boot学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 GraphQL APIs with Spring Bootコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
Subscription Resolvers Explained
Subscriptions deliver real-time updates. Unlike queries that return data once, subscription resolvers return a stream of data that continuously pushes updates to clients.
We'll learn how to implement these streams in a Spring Boot GraphQL application.
Embracing Reactor Flux
Spring GraphQL leverages Project Reactor's Flux to handle subscriptions. A Flux represents an asynchronous, non-blocking stream of 0 to N items.
- It's ideal for continuous data delivery.
- You can emit multiple values over time.
Schema for Real-time Updates
First, we define our subscription in the GraphQL Schema Definition Language (SDL). This example shows a subscription for new messages:
type Subscription {
messageAdded(channelId: ID!): Message
}
type Message {
id: ID!
text: String!
channelId: ID!
timestamp: String!
}Creating a Subscription Resolver
In Spring Boot, a subscription resolver is a method annotated with @SubscriptionMapping. It must return a Flux of the desired type.
We'll use a Sinks.Many to manage and publish events into this stream.
import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;
@Controller
public class MessageSubscriptionController {
private final Sinks.Many<Message> messageSink =
Sinks.many().multicast().onBackpressureBuffer();
@SubscriptionMapping
public Flux<Message> messageAdded() {
return messageSink.asFlux();
}
}Publishing Events with Sinks.Many
The Sinks.Many instance acts as our event publisher. When an event occurs (e.g., a new message is created), we use its tryEmitNext() method to send data into the stream.
This data then flows through the Flux to all connected GraphQL subscribers.
public class MessageService {
private final Sinks.Many<Message> messageSink;
public MessageService(Sinks.Many<Message> messageSink) {
this.messageSink = messageSink;
}
public Message createMessage(String text, String channelId) {
// ... save message to DB ...
Message newMessage = new Message("1", text, channelId, "now");
messageSink.tryEmitNext(newMessage); // Publish the new message
return newMessage;
}
}Full Runnable Example Setup
Let's build a complete, runnable Spring Boot application. We'll define a Message record and a MessagePublisher component to manage our Sinks.Many.
record Message(String id, String text, String channelId, String timestamp) {}
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;
@Component
public class MessagePublisher {
private final Sinks.Many<Message> messageSink =
Sinks.many().multicast().onBackpressureBuffer();
public Flux<Message> getMessageStream() {
return messageSink.asFlux();
}
public void publishMessage(Message message) {
messageSink.tryEmitNext(message);
}
}Main Application & Resolver
Now, we connect our MessagePublisher to the @SubscriptionMapping resolver. The Main class simulates sending a message after a delay.
Run this example to see the server-side publishing in action!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.graphql.data.method.annotation.SubscriptionMapping;
import org.springframework.stereotype.Controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
@SpringBootApplication
public class Main implements CommandLineRunner {
@Autowired
private MessagePublisher messagePublisher;
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
@Override
public void run(String... args) throws Exception {
// Simulate sending a message after 2 seconds
Mono.delay(Duration.ofSeconds(2))
.subscribe(l -> {
Message msg = new Message("2", "Hello from Spring!", "general", "now");
messagePublisher.publishMessage(msg);
System.out.println("Published: " + msg);
});
}
}
@Controller
class MessageSubscriptionController {
private final MessagePublisher messagePublisher;
public MessageSubscriptionController(MessagePublisher messagePublisher) {
this.messagePublisher = messagePublisher;
}
@SubscriptionMapping
public Flux<Message> messageAdded() {
return messagePublisher.getMessageStream();
}
}
record Message(String id, String text, String channelId, String timestamp) {}Filtering Subscription Events
Clients often need updates specific to certain criteria. We can filter the Flux based on arguments passed to the subscription.
Here, clients only receive messages for a specified channelId.
import org.springframework.graphql.data.method.annotation.Argument;
// ... other imports ...
@Controller
class MessageSubscriptionController {
private final MessagePublisher messagePublisher;
public MessageSubscriptionController(MessagePublisher messagePublisher) {
this.messagePublisher = messagePublisher;
}
@SubscriptionMapping
public Flux<Message> messageAdded(@Argument String channelId) {
return messagePublisher.getMessageStream()
.filter(msg -> msg.channelId().equals(channelId));
}
}Decoupling Event Publishing
For better architecture, it's a good practice to decouple event publishing from your core business logic.
- This keeps your services clean and focused.
- It allows multiple independent subscribers to react to the same event without tight coupling.
- Consider using Spring's
ApplicationEventPublisheror a dedicated event bus for this.
Subscription Resolver Check
You've learned how to implement subscription resolvers in Spring Boot. Let's test your understanding!
Recap: Real-time Updates
You've successfully learned how to implement real-time updates using GraphQL subscriptions in Spring Boot!
- Subscription resolvers return a
Flux. Sinks.Manyis used to publish events into theFlux.- You can filter streams based on subscription arguments.
- Decoupling publishing logic improves maintainability.
よくある質問
「リアルタイム更新の実装」レッスンは無料ですか?
はい。「リアルタイム更新の実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、GraphQL APIs with Spring Bootコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 GraphQL APIs with Spring Bootコースには全4レッスンが含まれています。
「リアルタイム更新の実装」で何を学びますか?
Spring BootでSubscription Resolverを開発し、イベントを公開してクライアントにライブデータを送信します。 ブラウザで直接実行するハンズオンコードでGraphQL APIs with Spring Bootを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
GraphQL APIs with Spring Bootを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGraphQL APIs with Spring Bootは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「リアルタイム更新の実装」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGraphQL APIs with Spring Bootレッスンでコードを書いて実行できますか?
はい。すべてのGraphQL APIs with Spring Bootレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。