You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义CDI Scope触发WELD-001303:无活动上下文问题求助

自定义CDI Scope报错:WELD-001303: No active contexts for scope type

问题背景

基于Jetty 11的嵌入式项目,已集成JPA、CDI、JMS和JAX-RS,原本运行正常。为添加自定义Scope,执行了以下操作:

  1. 定义@MyScoped注解:
@Inherited
@NormalScope
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScoped {}
  1. 实现Scope上下文类MyScopeContext:
import jakarta.enterprise.context.spi.Context;
import jakarta.enterprise.context.spi.Contextual;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;

import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class MyScopeContext implements Context {

    private final Map<Bean<?>, Object> instances = new ConcurrentHashMap<>();
    private final BeanManager beanManager;

    public MyScopeContext(BeanManager beanManager) {
        this.beanManager = beanManager;
    }

    @Override
    public Class<? extends Annotation> getScope() {
        return MyScoped.class;
    }

    @Override
    public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
        System.out.println("FLAG1");
        @SuppressWarnings("unchecked")
        Bean<T> bean = (Bean<T>) contextual;
        return (T) instances.computeIfAbsent(bean, b -> beanManager.getContext(bean.getScope()).get(bean, creationalContext));
    }

    @Override
    public <T> T get(Contextual<T> contextual) {
        System.out.println("FLAG2");
        @SuppressWarnings("unchecked")
        Bean<T> bean = (Bean<T>) contextual;
        return (T) instances.get(bean);
    }

    @Override
    public boolean isActive() {
        return true; // 原代码缺失分号,已修正
    }

    // 销毁上下文时清理实例
    public void destroy() {
        instances.clear();
    }
}
  1. 编写扩展类MyScopeExtension:
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.spi.*;

public class MyScopeExtension implements Extension {

    void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager manager) {
        BeanManager beanManager = CDI.current().getBeanManager();
        abd.addContext(new MyScopeContext(beanManager));
    }

    void addScope(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
        beforeBeanDiscovery.addScope(MyScoped.class, true, false);
    }

    // 原代码存在重复代码块,属于语法错误
    /*
    BeanManager beanManager = CDI.current().getBeanManager();
    afterBeanDiscovery.addContext(new MyScopeContext(beanManager));
    */
}
  1. 创建测试Bean:
@MyScoped
public class TempBean {
    public String say() {
        return "Hello world";
    }
}
  1. 在src/main/resources/META-INF/services/下创建jakarta.enterprise.inject.spi.Extension文件,内容为io.shaikezam.scope.MyScopeExtension。

报错信息

运行项目时抛出:

org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type io.shaikezam.scope.MyScoped

注意到构建后的jar中,扩展配置文件位于classes/META-INF/services/而非jar根目录的META-INF/services/,怀疑与此相关。项目pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>io.shaikezam</groupId>
        <artifactId>jakarta-system-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <artifactId>product-service</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-cdi2-se</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-client</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.jms</groupId>
            <artifactId>jakarta.jms-api</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.enterprise</groupId>
            <artifactId>jakarta.enterprise.cdi-api</artifactId>
        </dependency>
        <dependency>
            <groupId>io.shaikezam</groupId>
            <artifactId>utils</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    
</project>

问题分析与修复步骤

1. 修复扩展类语法错误

删除MyScopeExtension中的重复代码块,并优化BeanManager的获取方式:

import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.spi.*;

public class MyScopeExtension implements Extension {

    void addScope(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
        beforeBeanDiscovery.addScope(MyScoped.class, true, false);
    }

    void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager manager) {
        // 直接使用方法参数传入的BeanManager,避免容器初始化阶段调用CDI.current()的风险
        abd.addContext(new MyScopeContext(manager));
    }
}

2. 修正Scope上下文类的循环调用问题

原get方法中调用beanManager.getContext(bean.getScope()).get()会触发无限递归,因为当前上下文就是MyScoped对应的上下文,需改为直接创建实例:

@Override
public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) {
    System.out.println("FLAG1");
    @SuppressWarnings("unchecked")
    Bean<T> bean = (Bean<T>) contextual;
    return instances.computeIfAbsent(bean, b -> b.create(creationalContext));
}

3. 修复Maven打包资源路径问题

确保资源文件被正确打包到jar根目录:

  • 确认src/main/resources是Maven标准资源目录,若不是,在pom.xml中添加资源配置:
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*</include>
            </includes>
        </resource>
    </resources>
    <!-- 原有插件配置 -->
</build>
  • 配置maven-assembly-plugin正确包含资源文件,添加src/main/assembly/assembly.xml:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <id>jar-with-dependencies</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>${project.build.outputDirectory}</directory>
            <outputDirectory>/</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

然后在pom.xml中更新插件配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.6.0</version>
    <configuration>
        <descriptor>src/main/assembly/assembly.xml</descriptor>
        <archive>
            <manifest>
                <mainClass>你的主类全限定名</mainClass>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

4. 验证扩展加载

  • 确认jakarta.enterprise.inject.spi.Extension文件中的类名拼写无误,与实际类的全限定名一致。
  • 编译后检查target/classes/META-INF/services/下的文件是否存在,打包后检查jar根目录是否有META-INF/services/目录。

验证步骤

  1. 重新编译项目,检查资源文件路径是否正确。
  2. 执行打包命令,查看jar包结构是否符合预期。
  3. 运行项目,测试注入TempBean是否成功,不再抛出上下文未激活异常。

内容的提问来源于stack exchange,提问作者Shay Zambrovski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:45:54