# Shared Beans (Dependency Injection) Halo exposes several core beans that any plugin can inject via constructor injection. > Source references (Halo main branch): > > - [ReactiveExtensionClient](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/ReactiveExtensionClient.java) > - [ExtensionClient](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/ExtensionClient.java) > - [SchemeManager](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/SchemeManager.java) > - [ExtensionGetter](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/plugin/extensionpoint/ExtensionGetter.java) > - [UserService](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/core/user/service/UserService.java) > - [RoleService](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/core/user/service/RoleService.java) > - [AttachmentService](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/core/extension/service/AttachmentService.java) > - [PostContentService](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/content/PostContentService.java) > - [ExternalLinkProcessor](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/infra/ExternalLinkProcessor.java) > - [ExternalUrlSupplier](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java) > - [NotificationReasonEmitter](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/notification/NotificationReasonEmitter.java) > - [NotificationCenter](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/notification/NotificationCenter.java) > - [CryptoService](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/security/authentication/CryptoService.java) > - [RateLimiterRegistry](https://github.com/resilience4j/resilience4j/blob/master/resilience4j-ratelimiter/src/main/java/io/github/resilience4j/ratelimiter/RateLimiterRegistry.java) > - [ReactiveSettingFetcher](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/plugin/ReactiveSettingFetcher.java) > - [SettingFetcher](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/plugin/SettingFetcher.java) > - [PluginConfigUpdatedEvent](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/plugin/PluginConfigUpdatedEvent.java) > - [JsonUtils](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/infra/utils/JsonUtils.java) > - [ExtensionUtil](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/ExtensionUtil.java) > - [MetadataUtil](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/MetadataUtil.java) > - [PageRequestImpl](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/extension/PageRequestImpl.java) > - [SortResolver](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java) > - [AnonymousUserConst](https://github.com/halo-dev/halo/blob/main/api/src/main/java/run/halo/app/infra/AnonymousUserConst.java) ## Docs Routing This file lists frequently used beans, not every injectable type in Halo. For method signatures and newer APIs, verify against the official docs or source before coding. | Need | Official docs | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | ExtensionClient / ReactiveExtensionClient | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/extension-client.md | | ExtensionGetter and extension points | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/extension-getter.md | | SettingFetcher / ReactiveSettingFetcher | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/setting-fetcher.md | | Notifications | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/notification.md | | Reverse proxy helpers | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/reverseproxy.md | | WebSocket helpers | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/websocket.md | | Login handler enhancement | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/login-handler-enhancer.md | | Template and finder helpers for themes | https://raw.githubusercontent.com/halo-dev/docs/refs/heads/main/docs/developer-guide/plugin/api-reference/server/template-for-theme.md | When working from a local docs checkout, use the same paths under `docs/developer-guide/...`; versioned docs live under `versioned_docs/version-2.25/...`. ## Quick Index - Custom model CRUD: [ReactiveExtensionClient](#reactiveextensionclient) - Blocking model CRUD: [ExtensionClient](#extensionclient) - Extension point lookup: [ExtensionGetter](#extensiongetter) - Plugin settings: [SettingFetcher / ReactiveSettingFetcher](#settingfetcher--reactivesettingfetcher) - Notifications: [Notifications](#notifications) - JSON helpers: [JsonUtils](#jsonutils) ## ReactiveExtensionClient Reactive CRUD for custom extensions. ```java private final ReactiveExtensionClient client; // List with options client.listBy(Person.class, query.toListOptions(), query.toPageRequest()); // Get by name client.fetch(Person.class, "person-name"); // Create client.create(person); // Update client.update(person); // Delete client.delete(person); ``` ## ExtensionClient Blocking version of `ReactiveExtensionClient`. Use only in non-NIO threads (e.g., background tasks). ## SchemeManager Register/unregister custom extension types. ```java schemeManager.register(Person.class); schemeManager.register(Person.class, indexSpecs -> { /* ... */ }); schemeManager.unregister(Scheme.buildFromType(Person.class)); ``` ## ExtensionGetter Retrieve implementations of an extension point. ```java private final ExtensionGetter extensionGetter; // Get all implementations extensionGetter.getExtensions(AttachmentHandler.class); ``` ## UserService User operations: get info, update password, create users. ## ReactiveUserDetailsService ```java Mono findByUsername(String username); ``` ## RoleService Role operations: query roles, bindings, dependencies. ## AttachmentService Upload, delete, get access URLs for attachments. ## PostContentService Get post content with version management. ```java postContentService.getHeadContent(postName); // latest draft postContentService.getReleaseContent(postName); // published version postContentService.getSpecifiedContent(snapshotName); postContentService.listSnapshots(postName); ``` ## ExternalLinkProcessor Convert relative URLs to absolute using configured `externalUrl`. ```java externalLinkProcessor.processLink("/post/1"); // -> "https://example.com/post/1" ``` ## ExternalUrlSupplier Get the configured external URL. ## NotificationReasonEmitter / NotificationCenter Send notifications and manage subscriptions. ## ServerSecurityContextRepository Access authentication context. Required if your filter runs before Spring Security's `ReactorContextWebFilter`. ## CryptoService Decrypt login passwords or reuse the public key. ```java cryptoService.readPublicKey(); cryptoService.decrypt(encryptedPassword); ``` ## RateLimiterRegistry Create rate limiters (remember to clean up in `stop()`). ```java var rateLimiter = rateLimiterRegistry.rateLimiter(key, new RateLimiterConfig.Builder() .limitForPeriod(1) .limitRefreshPeriod(Duration.ofSeconds(60)) .build()); ``` ## SystemInfoGetter (Halo 2.20.11+) ```java Mono info = systemInfoGetter.get(); // Contains: title, subtitle, logo, favicon, url, version, seo, locale, timeZone, activatedThemeName ``` ## ReactiveSettingFetcher / SettingFetcher Fetch plugin configuration defined in `plugin.yaml` (`settingName` / `configMapName`). The fetcher caches values internally and auto-refreshes when configuration changes. **Reactive (WebFlux):** ```java private final ReactiveSettingFetcher settingFetcher; // Fetch a typed config object by group name settingFetcher.fetch("seo", SeoSetting.class) .doOnNext(seo -> { ... }); // Get raw JsonNode by group settingFetcher.getSettingValue("seo"); // Get all groups as a map settingFetcher.getSettingValues(); ``` **Blocking (background tasks / non-reactive code):** ```java private final SettingFetcher settingFetcher; Optional seo = settingFetcher.fetch("seo", SeoSetting.class); JsonNode raw = settingFetcher.getSettingValue("seo"); Map all = settingFetcher.getSettingValues(); ``` **Listen for config changes:** ```java @EventListener public void onConfigUpdated(PluginConfigUpdatedEvent event) { if (event.getNewConfig().containsKey("seo")) { // re-apply configuration } } ``` > **Prerequisite**: In `plugin.yaml`, declare `settingName: my-settings` and `configMapName: my-configmap`, and create a corresponding `settings.yaml` extension resource defining the form schema and groups. ## JsonUtils JSON serialization/deserialization utilities. > Note: `@Deprecated(forRemoval = true, since = "2.23.0")` — prefer `tools.jackson.databind.json.JsonMapper` in newer Halo versions. ```java // Object to JSON string String json = JsonUtils.objectToJson(myObject); // JSON string to object MyObject obj = JsonUtils.jsonToObject(json, MyObject.class); // JSON string with generics Set tags = JsonUtils.jsonToObject(json, new TypeReference<>() {}); // Map to object MyObject obj = JsonUtils.mapToObject(map, MyObject.class); // Deep copy MyObject copy = JsonUtils.deepCopy(original); // Access the underlying ObjectMapper ObjectMapper mapper = JsonUtils.mapper(); mapper.convertValue(data, new TypeReference<>() {}); ``` ## ExtensionUtil / MetadataUtil Utility methods for Extension lifecycle and metadata. ```java // Check deletion state boolean deleted = ExtensionUtil.isDeleted(extension); // Query for non-deleted resources (for ListOptions) ListOptions.builder().fieldQuery(ExtensionUtil.notDeleting()).build(); // Finalizer management ExtensionUtil.addFinalizers(metadata, Set.of("my-plugin/finalizer")); ExtensionUtil.removeFinalizers(metadata, Set.of("my-plugin/finalizer")); // Default sort: creationTimestamp desc, name asc Sort sort = ExtensionUtil.defaultSort(); // Safe metadata access (auto-initializes null collections) Map labels = MetadataUtil.nullSafeLabels(extension); Map annotations = MetadataUtil.nullSafeAnnotations(extension); ``` ## PageRequestImpl / PageRequest Pagination for list queries. Page numbers are **1-based**. ```java // Basic pagination PageRequestImpl.of(page, size); // page >= 1, size <= 1000 PageRequestImpl.of(page, size, Sort.by("name")); PageRequestImpl.ofSize(size); // page 1, given size // With sorting PageRequestImpl.of(1, 20, Sort.by( Sort.Order.desc("metadata.creationTimestamp"), Sort.Order.asc("metadata.name") )); ``` ## SortResolver / SortableRequest Resolve sorting from HTTP query parameters. ```java // In a CustomEndpoint handler Sort sort = SortResolver.defaultInstance.resolve(exchange); // Or extend SortableRequest for standardized list queries public class MyQuery extends SortableRequest { public MyQuery(ServerWebExchange exchange) { super(exchange); } public ListOptions toListOptions() { return labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector()); } } // Usage MyQuery query = new MyQuery(request.exchange()); client.listBy(MyExtension.class, query.toListOptions(), query.toPageRequest()); ``` Query parameter format: `?sort=field,asc` or `?sort=field,desc`. Multiple sorts: `?sort=field1,asc&sort=field2,desc`. ## AnonymousUserConst Check for anonymous users: ```java if (AnonymousUserConst.isAnonymousUser(authentication.getName())) { // Handle anonymous user } // Constants: AnonymousUserConst.PRINCIPAL ("anonymousUser"), AnonymousUserConst.Role ("anonymous") ``` ## BackupRootGetter / PluginsRootGetter `Supplier` for backup directory and plugin directory. ## LoginHandlerEnhancer Hook into login success/failure for custom logic.