diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcConfig.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcConfig.java
index 1c9b1f4c016296..5b8c1893fd1f7a 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcConfig.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcConfig.java
@@ -224,13 +224,21 @@ public class ArcConfig {
public ArcContextPropagationConfig contextPropagation;
/**
- * If set to {@code true}, the container should try to optimize the contexts for some of the scopes.
+ * If set to {@code true}, the container should try to optimize the contexts for some of the scopes. If set to {@code auto}
+ * then optimize the contexts if there's less than 1000 beans in the application. If set to {@code false} do not optimize
+ * the contexts.
*
* Typically, some implementation parts of the context for {@link jakarta.enterprise.context.ApplicationScoped} could be
* pregenerated during build.
*/
- @ConfigItem(defaultValue = "true", generateDocumentation = false)
- public boolean optimizeContexts;
+ @ConfigItem(defaultValue = "auto", generateDocumentation = false)
+ public OptimizeContexts optimizeContexts;
+
+ public enum OptimizeContexts {
+ TRUE,
+ FALSE,
+ AUTO
+ }
public final boolean isRemoveUnusedBeansFieldValid() {
return ALLOWED_REMOVE_UNUSED_BEANS_VALUES.contains(removeUnusedBeans.toLowerCase());
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
index dc44f9333bcc93..76a2b812a6ed02 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
@@ -16,6 +16,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -396,7 +397,23 @@ public Integer compute(AnnotationTarget target, Collection stere
}
builder.setBuildCompatibleExtensions(buildCompatibleExtensions.entrypoint);
- builder.setOptimizeContexts(arcConfig.optimizeContexts);
+ builder.setOptimizeContexts(new Function() {
+ @Override
+ public Boolean apply(BeanDeployment deployment) {
+ switch (arcConfig.optimizeContexts) {
+ case TRUE:
+ return true;
+ case FALSE:
+ return false;
+ case AUTO:
+ // Optimize the context if there is less than 1000 beans in the app
+ // Note that removed beans are excluded
+ return deployment.getBeans().size() < 1000;
+ default:
+ throw new IllegalArgumentException("Unexpected value: " + arcConfig.optimizeContexts);
+ }
+ }
+ });
BeanProcessor beanProcessor = builder.build();
ContextRegistrar.RegistrationContext context = beanProcessor.registerCustomContexts();
@@ -598,7 +615,7 @@ public ArcContainerBuildItem initializeContainer(ArcConfig config, ArcRecorder r
throws Exception {
ArcContainer container = recorder.initContainer(shutdown,
currentContextFactory.isPresent() ? currentContextFactory.get().getFactory() : null,
- config.strictCompatibility, config.optimizeContexts);
+ config.strictCompatibility);
return new ArcContainerBuildItem(container);
}
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsAutoTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsAutoTest.java
new file mode 100644
index 00000000000000..666c38dbc79f34
--- /dev/null
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsAutoTest.java
@@ -0,0 +1,35 @@
+package io.quarkus.arc.test.context.optimized;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ServiceLoader;
+
+import jakarta.inject.Inject;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.arc.ComponentsProvider;
+import io.quarkus.test.QuarkusUnitTest;
+
+public class OptimizeContextsAutoTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withApplicationRoot(root -> root
+ .addClasses(SimpleBean.class))
+ .overrideConfigKey("quarkus.arc.optimize-contexts", "auto");
+
+ @Inject
+ SimpleBean bean;
+
+ @Test
+ public void testContexts() {
+ assertTrue(bean.ping());
+ for (ComponentsProvider componentsProvider : ServiceLoader.load(ComponentsProvider.class)) {
+ // We have less than 1000 beans
+ assertFalse(componentsProvider.getComponents().getContextInstances().isEmpty());
+ }
+ }
+}
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsDisabledTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsDisabledTest.java
new file mode 100644
index 00000000000000..b1b611c81312ca
--- /dev/null
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/OptimizeContextsDisabledTest.java
@@ -0,0 +1,34 @@
+package io.quarkus.arc.test.context.optimized;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ServiceLoader;
+
+import jakarta.inject.Inject;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.arc.ComponentsProvider;
+import io.quarkus.test.QuarkusUnitTest;
+
+public class OptimizeContextsDisabledTest {
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .withApplicationRoot(root -> root
+ .addClasses(SimpleBean.class))
+ .overrideConfigKey("quarkus.arc.optimize-contexts", "false");
+
+ @Inject
+ SimpleBean bean;
+
+ @Test
+ public void testContexts() {
+ assertTrue(bean.ping());
+ for (ComponentsProvider componentsProvider : ServiceLoader.load(ComponentsProvider.class)) {
+ assertTrue(componentsProvider.getComponents().getContextInstances().isEmpty());
+ }
+ }
+
+}
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/SimpleBean.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/SimpleBean.java
new file mode 100644
index 00000000000000..0c545a000a5b01
--- /dev/null
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/context/optimized/SimpleBean.java
@@ -0,0 +1,12 @@
+package io.quarkus.arc.test.context.optimized;
+
+import jakarta.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+class SimpleBean {
+
+ public boolean ping() {
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java
index 23ffb5196720de..4c1ecac85a7122 100644
--- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java
+++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java
@@ -42,12 +42,10 @@ public class ArcRecorder {
public static volatile Map, ?>> syntheticBeanProviders;
public ArcContainer initContainer(ShutdownContext shutdown, RuntimeValue currentContextFactory,
- boolean strictCompatibility, boolean optimizeContexts)
- throws Exception {
+ boolean strictCompatibility) throws Exception {
ArcInitConfig.Builder builder = ArcInitConfig.builder();
builder.setCurrentContextFactory(currentContextFactory != null ? currentContextFactory.getValue() : null);
builder.setStrictCompatibility(strictCompatibility);
- builder.setOptimizeContexts(optimizeContexts);
ArcContainer container = Arc.initialize(builder.build());
shutdown.addShutdownTask(new Runnable() {
@Override
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
index beb80d5153a809..d041fbba42c73f 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
@@ -78,7 +78,7 @@ public static Builder builder() {
private final boolean generateSources;
private final boolean allowMocking;
private final boolean transformUnproxyableClasses;
- private final boolean optimizeContexts;
+ private final Function optimizeContexts;
private final List>> suppressConditionGenerators;
// This predicate is used to filter annotations for InjectionPoint metadata
@@ -187,6 +187,7 @@ public List generateResources(ReflectionRegistration reflectionRegistr
ReflectionRegistration refReg = reflectionRegistration != null ? reflectionRegistration : this.reflectionRegistration;
PrivateMembersCollector privateMembers = new PrivateMembersCollector();
+ boolean optimizeContextsValue = optimizeContexts != null ? optimizeContexts.apply(beanDeployment) : false;
// These maps are precomputed and then used in the ComponentsProviderGenerator which is generated first
Map beanToGeneratedName = new HashMap<>();
@@ -240,7 +241,7 @@ public List generateResources(ReflectionRegistration reflectionRegistr
ContextInstancesGenerator contextInstancesGenerator = new ContextInstancesGenerator(generateSources,
refReg, beanDeployment, scopeToGeneratedName);
- if (optimizeContexts) {
+ if (optimizeContextsValue) {
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.APPLICATION.getName());
contextInstancesGenerator.precomputeGeneratedName(BuiltinScope.REQUEST.getName());
}
@@ -364,7 +365,7 @@ public Collection call() throws Exception {
}));
}
- if (optimizeContexts) {
+ if (optimizeContextsValue) {
// Generate _ContextInstances
primaryTasks.add(executor.submit(new Callable>() {
@@ -450,7 +451,7 @@ public Collection call() throws Exception {
observerToGeneratedName,
scopeToGeneratedName));
- if (optimizeContexts) {
+ if (optimizeContextsValue) {
// Generate _ContextInstances
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.APPLICATION.getName()));
resources.addAll(contextInstancesGenerator.generate(BuiltinScope.REQUEST.getName()));
@@ -564,7 +565,7 @@ public static class Builder {
boolean failOnInterceptedPrivateMethod;
boolean allowMocking;
boolean strictCompatibility;
- boolean optimizeContexts;
+ Function optimizeContexts;
AlternativePriorities alternativePriorities;
final List> excludeTypes;
@@ -600,7 +601,6 @@ public Builder() {
failOnInterceptedPrivateMethod = false;
allowMocking = false;
strictCompatibility = false;
- optimizeContexts = false;
excludeTypes = new ArrayList<>();
@@ -842,7 +842,21 @@ public Builder setStrictCompatibility(boolean strictCompatibility) {
* @return self
*/
public Builder setOptimizeContexts(boolean value) {
- this.optimizeContexts = value;
+ return setOptimizeContexts(new Function() {
+ @Override
+ public Boolean apply(BeanDeployment t) {
+ return value;
+ }
+ });
+ }
+
+ /**
+ *
+ * @param fun
+ * @return self
+ */
+ public Builder setOptimizeContexts(Function fun) {
+ this.optimizeContexts = fun;
return this;
}