diff --git a/application/src/main/java/run/halo/app/cache/CacheConditionProvider.java b/application/src/main/java/run/halo/app/cache/CacheConditionProvider.java new file mode 100644 index 000000000..fd51a2f27 --- /dev/null +++ b/application/src/main/java/run/halo/app/cache/CacheConditionProvider.java @@ -0,0 +1,100 @@ +package run.halo.app.cache; + +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; +import run.halo.app.extension.ReactiveExtensionClientImpl; +import run.halo.app.infra.properties.HaloProperties; + +/** + * Provides methods to determine if specific types of caches are evictable or enabled. + * + *
Uses {@link HaloProperties} to check the configuration for cache settings.
+ *
+ * @author sergei
+ * @see HaloProperties#getCaches()
+ * @see Cacheable#condition()
+ * @see CacheEvict#condition()
+ * @see ReactiveExtensionClientImpl
+ */
+@Component
+@RequiredArgsConstructor
+public class CacheConditionProvider {
+ private static final String ROLE_KIND = "Role";
+ private static final String PLUGIN_KIND = "Plugin";
+ private static final String EXTENSION_POINT_DEFINITION_KIND = "ExtensionPointDefinition";
+
+ private final HaloProperties properties;
+
+ /**
+ * Determines if the role dependencies cache is evictable based on the provided kind.
+ *
+ * @param kind the kind to check against.
+ * @return {@code true} if the role dependencies cache is evictable, {@code false} otherwise.
+ */
+ public boolean isRoleDependenciesCacheEvictableByKind(String kind) {
+ return isRoleCacheEnabled() && Objects.equals(kind, ROLE_KIND);
+ }
+
+ /**
+ * Determines if the plugin extension cache is evictable based on the provided kind.
+ *
+ * @param kind the kind to check against.
+ * @return {@code true} if the plugin extension cache is evictable, {@code false} otherwise.
+ */
+ public boolean isPluginExtensionCacheEvictableByKind(String kind) {
+ return isPluginExtensionCacheEnabled() && Objects.equals(kind, PLUGIN_KIND);
+ }
+
+ /**
+ * Determines if the extension point definition cache is evictable based on the provided kind.
+ *
+ * @param kind the kind to check against.
+ * @return {@code true} if the extension point definition cache is evictable, {@code false}
+ * otherwise.
+ */
+ public boolean isExtensionPointDefinitionCacheEvictableByKind(String kind) {
+ return isExtensionPointDefinitionCacheEnabled() && Objects.equals(kind,
+ EXTENSION_POINT_DEFINITION_KIND);
+ }
+
+ /**
+ * Checks if the role dependencies cache is enabled.
+ *
+ * @return {@code true} if the role dependencies cache is enabled, {@code false} otherwise
+ */
+ public boolean isRoleCacheEnabled() {
+ return isCacheEnabled("role-dependencies");
+ }
+
+ /**
+ * Checks if the plugin extension cache is enabled.
+ *
+ * @return {@code true} if the plugin extension cache is enabled, {@code false} otherwise.
+ */
+ public boolean isPluginExtensionCacheEnabled() {
+ return isCacheEnabled("plugin-extension");
+ }
+
+ /**
+ * Checks if the extension point definition cache is enabled.
+ *
+ * @return {@code true} if the extension point definition cache is enabled, {@code false}
+ * otherwise.
+ */
+ public boolean isExtensionPointDefinitionCacheEnabled() {
+ return isCacheEnabled("extension-point-definition");
+ }
+
+ private boolean isCacheEnabled(String cache) {
+ var cacheProperties = properties.getCaches().get(cache);
+
+ if (cacheProperties != null) {
+ return !cacheProperties.isDisabled();
+ }
+
+ return false;
+ }
+}
diff --git a/application/src/main/java/run/halo/app/cache/CacheNames.java b/application/src/main/java/run/halo/app/cache/CacheNames.java
new file mode 100644
index 000000000..f19d1c624
--- /dev/null
+++ b/application/src/main/java/run/halo/app/cache/CacheNames.java
@@ -0,0 +1,41 @@
+package run.halo.app.cache;
+
+import java.util.Set;
+import run.halo.app.core.extension.service.DefaultRoleService;
+import run.halo.app.extension.ReactiveExtensionClientImpl;
+import run.halo.app.plugin.extensionpoint.DefaultExtensionGetter;
+
+/**
+ * Defines constant cache names used in the application.
+ *
+ * @author sergei
+ */
+public final class CacheNames {
+
+ /**
+ * Cache name for dependencies roles.
+ *
+ * @see DefaultRoleService#listDependenciesFlux(Set)
+ * @see ReactiveExtensionClientImpl
+ */
+ public static final String ROLE_DEPENDENCIES = "ROLE_DEPENDENCIES";
+
+ /**
+ * Cache name for plugin extensions.
+ *
+ * @see DefaultExtensionGetter#getExtensions(Class)
+ * @see ReactiveExtensionClientImpl
+ */
+ public static final String PLUGIN_EXTENSIONS = "PLUGIN_EXTENSIONS";
+
+ /**
+ * Cache name for plugin extensions.
+ *
+ * @see DefaultExtensionGetter#getEnabledExtensionByDefinition(Class)
+ * @see ReactiveExtensionClientImpl
+ */
+ public static final String EXTENSION_POINT_DEFINITIONS = "EXTENSION_POINT_DEFINITIONS";
+
+ private CacheNames() {
+ }
+}
diff --git a/application/src/main/java/run/halo/app/config/postproccessor/CaffeineCacheManagerPostProcessor.java b/application/src/main/java/run/halo/app/config/postproccessor/CaffeineCacheManagerPostProcessor.java
new file mode 100644
index 000000000..43658d056
--- /dev/null
+++ b/application/src/main/java/run/halo/app/config/postproccessor/CaffeineCacheManagerPostProcessor.java
@@ -0,0 +1,32 @@
+package run.halo.app.config.postproccessor;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.cache.caffeine.CaffeineCacheManager;
+import org.springframework.lang.NonNull;
+import org.springframework.stereotype.Component;
+
+/**
+ * Post-processes of {@link CaffeineCacheManager} beans to enabled async mode for them after
+ * initialization.
+ *
+ * @author sergei
+ * @see CaffeineCacheManager#setAsyncCacheMode(boolean)
+ */
+@Component
+public class CaffeineCacheManagerPostProcessor implements BeanPostProcessor {
+
+ @Override
+ public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName)
+ throws BeansException {
+ if (bean instanceof CaffeineCacheManager cacheManager) {
+ configure(cacheManager);
+ }
+
+ return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
+ }
+
+ private void configure(CaffeineCacheManager caffeineCacheManager) {
+ caffeineCacheManager.setAsyncCacheMode(true);
+ }
+}
diff --git a/application/src/main/java/run/halo/app/core/extension/service/DefaultRoleService.java b/application/src/main/java/run/halo/app/core/extension/service/DefaultRoleService.java
index 2feb50f87..949c89dc8 100644
--- a/application/src/main/java/run/halo/app/core/extension/service/DefaultRoleService.java
+++ b/application/src/main/java/run/halo/app/core/extension/service/DefaultRoleService.java
@@ -13,11 +13,13 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.cache.annotation.Cacheable;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import run.halo.app.cache.CacheNames;
import run.halo.app.core.extension.Role;
import run.halo.app.core.extension.RoleBinding;
import run.halo.app.core.extension.RoleBinding.RoleRef;
@@ -72,6 +74,10 @@ public class DefaultRoleService implements RoleService {
}
@Override
+ @Cacheable(
+ value = CacheNames.ROLE_DEPENDENCIES,
+ condition = "@cacheConditionProvider.isRoleCacheEnabled()"
+ )
public Flux