Spring Boot集成Togglz时ServiceConfigurationError异常解决
问题现象
运行应用时抛出以下异常:
Exception in thread "main" java.util.ServiceConfigurationError: org.togglz.core.spi.BeanFinder: org.togglz.cdi.spi.CDIBeanFinder Unable to get public no-arg constructor
at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:586)
at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:679)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1240)
at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273)
at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1309)
at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1393)
at org.togglz.core.context.BeanFinderFeatureManagerProvider.getFeatureManager(BeanFinderFeatureManagerProvider.java:36)
at org.togglz.core.context.FeatureContext.findFeatureManagerInClassLoader(FeatureContext.java:107)
at org.togglz.core.context.FeatureContext.getFeatureManagerOrNull(FeatureContext.java:73)
at org.togglz.core.context.FeatureContext.getFeatureManager(FeatureContext.java:46)
at com.paulcarron.testproject.MyFeatures.isActive(MyFeatures.java:18)
at com.paulcarron.testproject.TogglzTest.getTogglzStatus(TogglzTest.java:31)
at com.paulcarron.testproject.TestprojectApplication.main(TestprojectApplication.java:15)
Caused by: java.lang.NoClassDefFoundError: javax/enterprise/context/spi/Contextual
at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3405)
at java.base/java.lang.Class.getConstructor0(Class.java:3610)
at java.base/java.lang.Class.getConstructor(Class.java:2303)
at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:666)
at java.base/java.util.ServiceLoader$1.run(ServiceLoader.java:663)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
at java.base/java.util.ServiceLoader.getConstructor(ServiceLoader.java:674)
... 11 more
Caused by: java.lang.ClassNotFoundException: javax.enterprise.context.spi.Contextual
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 19 more
相关代码
TogglzTest代码片段:
if(MyFeatures.FEATURE_ONE.isActive() ) { System.out.println("togglzOff is " + togOnTrue); System.out.println("togglzOff is " + togOnFalse); }
MyFeatures的isActive方法:
public boolean isActive() { return FeatureContext.getFeatureManager().isActive(this); }
问题根源
- 冗余且不兼容的CDI依赖:引入了
togglz-cdi依赖,但Spring Boot 3基于Jakarta EE规范,而javax.enterprise.context.spi.Contextual属于旧Java EE包,你添加的Jakarta版本CDI API与旧依赖不匹配,导致类找不到。 - Togglz版本不一致:pom中
togglz-servlet、togglz-cdi、togglz-spring-web为3.1.2版本,togglz-spring-core为3.3.3版本,版本差异引发兼容性问题。 - 不必要的依赖加载:Spring Boot环境下无需CDI集成,多余的CDI依赖会让Togglz尝试加载CDIBeanFinder,触发异常。
解决方案
步骤1:移除CDI相关依赖
删除pom中的以下依赖:
<!-- CDI integration (optional) --> <dependency> <groupId>org.togglz</groupId> <artifactId>togglz-cdi</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <version>4.0.1</version> </dependency>
步骤2:统一Togglz版本
将所有Togglz依赖版本统一为3.3.3,修改后如下:
<!-- Togglz Servlet核心依赖 --> <dependency> <groupId>org.togglz</groupId> <artifactId>togglz-servlet</artifactId> <version>3.3.3</version> </dependency> <!-- Togglz Spring Web集成 --> <dependency> <groupId>org.togglz</groupId> <artifactId>togglz-spring-web</artifactId> <version>3.3.3</version> </dependency> <!-- Togglz Spring Core集成 --> <dependency> <groupId>org.togglz</groupId> <artifactId>togglz-spring-core</artifactId> <version>3.3.3</version> </dependency>
步骤3:添加Togglz配置类
创建Spring配置类,确保FeatureManager被正确加载到上下文:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.togglz.core.manager.FeatureManager; import org.togglz.core.manager.FeatureManagerBuilder; import org.togglz.core.repository.StateRepository; import org.togglz.core.repository.mem.InMemoryStateRepository; import org.togglz.core.user.NoOpUserProvider; @Configuration public class TogglzConfig { @Bean public FeatureManager featureManager() { return new FeatureManagerBuilder() .featureEnum(MyFeatures.class) .stateRepository(stateRepository()) .userProvider(new NoOpUserProvider()) .build(); } @Bean public StateRepository stateRepository() { return new InMemoryStateRepository(); } }
步骤4:验证修改
重新构建并运行应用,检查异常是否消失,确认MyFeatures.FEATURE_ONE.isActive()可正常调用。
内容的提问来源于stack exchange,提问作者runnerpaul

