{"id":18559008,"url":"https://github.com/linux-china/nats-spring-boot-starter","last_synced_at":"2025-04-10T01:33:11.355Z","repository":{"id":136595748,"uuid":"132283823","full_name":"linux-china/nats-spring-boot-starter","owner":"linux-china","description":"Spring Boot starter for NATS","archived":false,"fork":false,"pushed_at":"2024-12-14T03:17:01.000Z","size":392,"stargazers_count":30,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-02T02:51:12.204Z","etag":null,"topics":["mq","nats","spring-boot-starter"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linux-china.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-05T20:55:39.000Z","updated_at":"2025-02-04T15:12:04.000Z","dependencies_parsed_at":"2024-03-17T17:24:00.388Z","dependency_job_id":"da258b6d-7e03-4add-8110-bfc98dedaa33","html_url":"https://github.com/linux-china/nats-spring-boot-starter","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-china%2Fnats-spring-boot-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-china%2Fnats-spring-boot-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-china%2Fnats-spring-boot-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linux-china%2Fnats-spring-boot-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linux-china","download_url":"https://codeload.github.com/linux-china/nats-spring-boot-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248140798,"owners_count":21054353,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mq","nats","spring-boot-starter"],"created_at":"2024-11-06T21:41:50.258Z","updated_at":"2025-04-10T01:33:06.325Z","avatar_url":"https://github.com/linux-china.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Spring Boot Starter NATS\n===========================\nSpring Boot 2.x/3.x starter for NATS with Publish/Subscribe, Services Framework, JetStream KV watch support.\n\n![architecture](architecture.png)\n\n# Why Spring Boot starter for NATS?\n\nNATS is very simple, why you create a starter for Spring Boot?\n\n* Nats Microservices framework support: RPC style with `json`, `protobuf`, `avro` data format.\n* JetStream KeyValue watch support: durable Component and state sync between instances.\n* NATS service interface: almost alike Spring HTTP interface to make services call easy\n* Spring Kafka like: `@NatsSubscriber` to listen subject\n* Subject(UUID) for instance only: make A/B easy\n* NatsTemplate: friendly with Spring `XxxTemplate` style\n* Metrics \u0026 endpoints: `/actuator/nats`, NATS information/statistics\n* Health indicator for NATS\n* NATS Protocol Binding for CloudEvents\n\n# Get Started with Publish/Subscribe\n\n* please add following dependency in your pom.xml\n\n```xml\n\n\u003cdependency\u003e\n  \u003cgroupId\u003eorg.mvnsearch\u003c/groupId\u003e\n  \u003cartifactId\u003enats-spring-boot-starter\u003c/artifactId\u003e\n  \u003cversion\u003e0.2.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n* please add setting in application.properties. For cluster, please change url to \"nats://host1:4222,nats://host2:4222\"\n\n```\nnats.spring.server = nats://localhost:4222\nnats.spring.connection-name=${spring.application.name}.${random.uuid}\n```\n\n* in you code, use NatsTemplate to send message\n\n```\n   @Autowired\n   private NatsTemplate natsTemplate;\n   ...\n   natsTemplate.publish(\"subject1\",\"hello\".getBytes());\n```\n\n* @NatsSubscriber support, method signature of subscriber is `\"(Message)-\u003evoid\"`\n\n```\n    @NatsSubscriber(subject = \"topic.a\")\n    public void handler(Message msg) {\n}\n```\n\n### Subject for App Instance only\n\nEvery app instance will listen a subject, such as `app-name-75454360-49f0-4609-9ed9-1e3bef4219cc`(print on console),\nand you can send the messages to the subject and communicate with the instance only.\n\nIt's easy and simple, and you can use `AppInstanceOnlyMessageHandler` interface to handle the message.\n\n```java\n\n@SpringBootApplication\npublic class NatsDemoApplication implements AppInstanceOnlyMessageHandler {\n\n  public static void main(String[] args) {\n    SpringApplication.run(NatsDemoApplication.class, args);\n  }\n\n  @Override\n  public void onMessage(Message msg) throws InterruptedException {\n    System.out.println(\"Received message from:\" + msg.getSubject());\n  }\n}\n```\n\nSome use cases for this feature:\n\n* Peer-to-Peer communication: send messages to a specific instance.\n* A/B testing: send the message to a specific instance, and not broadcast to all instances.\n\n\n# NATS MicroServices framework\n\n[NATS Services Framework](https://natsbyexample.com/examples/services/intro/java) is MicroServices RPC framework with\nService Discovery support,\nand you can\ncheck [NATS Service API Spec](https://github.com/nats-io/nats-architecture-and-design/blob/main/adr/ADR-32.md) for\ndetail.\n\n### How to publish NATS MicroServices?\n\nIn the server side, create a normal Spring Boot controller with `@MessageMapping` and `@NatsService` annotations.\n\n```java\n\n@Controller\n@MessageMapping(\"minmax\")\n@NatsService(name = \"minmax\", version = \"0.0.1\", description = \"min/max number service\")\npublic class UserNatsService {\n\n  @MessageMapping(\"min\")\n  public int min(@Payload String body) {\n    int min = Integer.MAX_VALUE;\n    String[] input = body.split(\",\");\n    for (String n : input) {\n      min = Math.min(min, Integer.parseInt(n));\n    }\n    return min;\n  }\n}\n```\n\nPlease\nrefer [MessageMapping](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/handler/annotation/MessageMapping.html)\nfor arguments binding. Now only following annotations supported:\n\n* `@Payload String body` or `String body`: bind the message body to the method parameter\n* `@Header(\"contentType\") String contentType`: bind the message header to the method parameter\n* `@Headers Map\u003cString, Object\u003e headers`: bind the destination variable to the method parameter\n\nAfter server started, and you can use `nats micro ls` to check services, and use `nats request minmax.min \"1,2\"` to make\na test.\n\n### How to consume NATS MicroServices?\n\nIn the client side, create an interface with `@NatsExchange` and add methods with `@ServiceExchange` annotations.\n\n```java\n\n@NatsExchange\npublic interface UserService {\n\n  @ServiceExchange(\"minmax.min\")\n  Mono\u003cInteger\u003e min(String text);\n}\n```\n\nThen to build service stub proxy to call the service.\n\n```java\npublic class UserServiceTest {\n\n  @Test\n  public void testServiceCall() throws Exception {\n    Connection nc = Nats.connect(\"nats://localhost:4222\");\n    UserService userService = NatsExchangeProxyFactory.buildStub(nc, UserService.class);\n    Integer min = userService.min(\"1,2\").block();\n    System.out.println(min);\n  }\n}\n```\n\n**Attention**: NATS MicroServices frameworks is based on `request-reply` model, and it is async mode, and you need to\nuse Reactive `Mono` to handle the result.\n\n### Object serialization for NATS Services\n\nIf you want to use JSON, and you can use `@NatsExchange` annotation to specify the content type as following:\n\n```java\n\n@NatsExchange(value = \"nats://localhost:4222\", path = \"UserService\", contentType = \"application/json\")\npublic interface UserService {\n  @ServiceExchange(\"hello\")\n  Mono\u003cString\u003e hello(User user);\n}\n```\n\nThe following content types are supported:\n\n* Jackson(application/json):  https://github.com/FasterXML/jackson\n* Protobuf(application/x-protobuf): https://developers.google.com/protocol-buffers/\n* Avro(application/avro): https://avro.apache.org/ friendly with Kafka Schema\n\nIf you choose Protobuf, and it's better to add `content-type` and `message-type` headers in NATS message.\n\n```\ncontent-type: application/x-protobuf\nmessage-type: org.mvnsearch.User\n```\n\n# Durable Component\n\nDurable component is almost like [Cloudflare Durable Objects](https://developers.cloudflare.com/durable-objects/),\nand you can use NATS JetStream KV watch to sync states between instances.\n\n```java\n\n@Component\n@NatsDurableComponent\npublic class OnlineUserComponent {\n  private static final Logger logger = LoggerFactory.getLogger(OnlineUserComponent.class);\n  private int onlineUserCount;\n\n  @NatsKeyWatcher(bucket = \"bucket\", key = \"online.user.count\")\n  public void setOnlineUserCount(int count) {\n    logger.info(\"Online user count: \" + count);\n    this.onlineUserCount = count;\n  }\n}\n```\n\nAfter `bucket/online.user.count` key changed, the `setOnlineUserCount` method will be called to sync the state between\ninstances.\n\n**Tips**: If you have a state with many fields, and you can use JavaBean or `record` as fields.\nThen call `nats kv put bucket online.admin '{\"nick\": \"linux_china\", \"phone\":\"138xxx\"}'` to update JavaBean state.\n\n# NATS KeyValue store\n\n[NATS KeyValue Store](https://docs.nats.io/nats-concepts/jetstream/key-value-store) is a nice feature for some cases:\n\n* Configuration Data: watch support\n* Metadata: Data Schema, such as avro, protobuf, json schema etc under `schema-registry` bucket.\n* State data: cooperate with instances, such as rate limit, black list etc.\n\n# NATS Object Store\n\n[NATS Object Store](https://docs.nats.io/nats-concepts/jetstream/obj_store) is a nice feature for some cases:\n\n* Workload binary storage: such as Wasm module, JS bundle etc.\n* Statics Data: some data for report(short-time), such as CSV, JSON etc.\n* Callback support: watch support for bucket.\n\n# Spring Cloud Stream Binder for NATS\n\nUse official Spring Cloud Stream Binder for\nNATS [nats-spring-cloud-stream-binder](https://github.com/nats-io/spring-nats).\n\n**Tips**: nats-spring-boot-starter is based on spring-nats, and you can use both of them in your project.\n\n# Spring Boot Actuator\n\nPlease visit `/actuator/nats` for NATS information and statistics.\n\n* NATS Server Information\n* NATS Services\n* Nats Subscribers\n* Disconnect from NATS: Graceful shutdown - `POST /actuator/nats/offline`\n\n# NATS Protocol Binding for CloudEvents\n\nPlease refer [NATS Protocol Binding for CloudEvents](https://github.com/cloudevents/spec/blob/main/cloudevents/bindings/nats-protocol-binding.md).\n\nNATS Message's `Content-Type` header value: `application/cloudevents+json`。\n\nConvert NATS Message to CloudEvent:\n\n```\n    EventFormat format = EventFormatProvider.getInstance().resolveFormat(JsonFormat.CONTENT_TYPE);\n    if (msg.getHeaders().getFirst(\"Content-Type\").equals(format.serializedContentType())) {\n       final CloudEvent cloudEvent = format.deserialize(msg.getData());\n    }\n```\n\n# GraphQL over NATS\n\nGraphQL service interface definition.\n\n```\npublic interface GraphqlService {\n\n    Mono\u003cString\u003e query(String query, Map\u003cString, Object\u003e variables);\n\n    Mono\u003cString\u003e mutation(String mutation, Map\u003cString, Object\u003e variables);\n\n    Flux\u003cString\u003e subscription(String subscription, Map\u003cString, Object\u003e variables);\n}\n```\n\n### query/mutation\nServices Framework(request-reply)\n\n### subscription\n\n* Subscribe a subject, such as \"graphql.sub.xxxx\"\n* Send request-reply, message with \"subscribed-to\" header, and the value is the subject\n* Received the replied message. If payload is ok, then you can receive the subscription message. otherwise, unsubscribe the subject.\n\n# Todo\n\n* Data schema metadata for services: such as json schema, load schema file from classpath or annotation?\n* Graceful shutdown: call actuator endpoint to disconnect from NATS?\n\n# References\n\n* NATS:  https://nats.io/\n* NATS Docs: https://docs.nats.io/\n* NATS Architecture and Design Docs: https://github.com/nats-io/nats-architecture-and-design\n* NATS Java client: https://github.com/nats-io/nats.java\n* spring-nats: https://github.com/nats-io/spring-nats\n* Monitoring NATS: https://docs.nats.io/running-a-nats-service/nats_admin/monitoring\n* Method Handles in Java: http://www.baeldung.com/java-method-handles\n* EventCatalog: Documentation tool for Event-Driven Architectures - https://www.eventcatalog.dev/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinux-china%2Fnats-spring-boot-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinux-china%2Fnats-spring-boot-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinux-china%2Fnats-spring-boot-starter/lists"}