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

如何在WSS4JOutInterceptor的CallbackHandler中注入@AppConfigProperty

问题解答

你的猜想完全正确。

原因分析

当你通过ConfigurationConstants.PW_CALLBACK_CLASS指定InternalServicePasswordCallback的类名时,WSS4J会直接通过反射自行实例化这个回调类,整个过程完全脱离JBoss/Weld CDI容器的管理。CDI的依赖注入仅对由容器创建和托管的Bean实例生效,因此你注入的username字段始终为null。

解决方案

要让CDI注入生效,需要让WSS4J使用CDI托管的回调实例,而不是让它自行创建。具体有两种简单可行的方式:

方式1:直接传入CDI托管的回调实例

  1. 首先确保InternalServicePasswordCallback被CDI识别为托管Bean,给它添加CDI作用域注解,比如@Dependent(最适合回调类的作用域):
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;

@Dependent
public class InternalServicePasswordCallback implements CallbackHandler {
    private static final String APP_PROPERTIES = "app.properties";
 
    @Inject
    @AppConfigProperty("USERNAME")
    private String username;
 
    // 原构造方法和handle方法保持不变
}
  1. 在调用setEndPoint的类中,注入这个回调实例:
@Inject
private InternalServicePasswordCallback passwordCallback;
  1. 修改WSS4J的配置,替换PW_CALLBACK_CLASS为PW_CALLBACK_REF,直接传入已注入好的实例:
private void setEndPoint(Object port, String endPoint) {      
    BindingProvider bp = (BindingProvider) port;
    bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endPoint);
    Client client = ClientProxy.getClient(port);
     
    Map<String, Object> props = new HashMap<>();
    props.put(ConfigurationConstants.ACTION, ConfigurationConstants.USERNAME_TOKEN);
    props.put(ConfigurationConstants.PASSWORD_TYPE, WSS4JConstants.PW_TEXT);
    // 替换为传入CDI托管的实例
    props.put(ConfigurationConstants.PW_CALLBACK_REF, passwordCallback);
    props.put(ConfigurationConstants.USER, user);
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
    Endpoint endpoint = client.getEndpoint();
    endpoint.getOutInterceptors().add(wssOut);
     
    client.getOutInterceptors().add(new LoggingOutInterceptor(-1));
    client.getInInterceptors().add(new LoggingInInterceptor(-1));
}

方式2:自定义回调工厂(可选,适合复杂场景)

如果无法直接注入实例,可以自定义一个CallbackHandlerFactory,通过CDI的BeanManager获取回调实例,再配置给WSS4J:

public class CDICallbackHandlerFactory implements CallbackHandlerFactory {
    @Override
    public CallbackHandler createCallbackHandler(Map<String, Object> props) {
        BeanManager beanManager = CDI.current().getBeanManager();
        return beanManager.createInstance().select(InternalServicePasswordCallback.class).get();
    }
}

然后在WSS4J配置中指定工厂类:

props.put(ConfigurationConstants.CALLBACK_HANDLER_FACTORY, CDICallbackHandlerFactory.class.getName());

注意事项

  • 确保你的应用归档(WAR/JAR)包含beans.xml文件(即使是空文件),让CDI能够扫描并识别托管Bean。
  • 如果是在批处理作业环境中调用,需要确保当前上下文处于CDI活动范围内(JBoss EAP的批处理组件通常会自动处理,但如果遇到问题,可以通过CDI.current()手动获取上下文)。

内容的提问来源于stack exchange,提问作者Cristian-Florin Pandele

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 17:39:24