【问题标题】:CXF Interceptor phases being skipped for missing phase declarationCXF 拦截器阶段因缺少阶段声明而被跳过
【发布时间】:2019-06-04 23:52:38
【问题描述】:

在这方面工作了一段时间,但没有任何运气。

我正在从 Spring 3.2.9 升级到 4.2.6。我的第一步是升级到 cxf-core 3.1.6,我这样做并没有对应用程序造成任何问题。

在升级所有 spring 依赖项时,我遇到了拦截器设置的问题。以下是基础知识:

拦截器

public class MyInterceptor extends AbstractPhaseInterceptor<Message>{

private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

public MyInterceptor() {
    super(Phase.PRE_INVOKE);
    addAfter(HolderInInterceptor.class.getName());
}

@PostConstruct
public void display() {
    logger.warn(this.getPhase());
}


@Override
public void handleMessage(Message message) throws Fault {
    ....

cxfContext.xml

<bean id="contentInInterceptor" class="com.MyInterceptor">
</bean>

<cxf:bus>
    <cxf:inInterceptors>
        <ref bean="contentInInterceptor"/>
    </cxf:inInterceptors>


</cxf:bus>

以及它被添加到 web.xml 中。运行时,我看到记录的信息显示拦截器是使用预调用阶段创建的(我添加了这个以验证我不会发疯)。但是在调用服务时,PhaseInterceptor 链会因为未声明阶段而跳过拦截器:

日志:

2016-05-31 16:08:28,208 [localhost-startStop-1] [] 警告 c.MyInterceptor - 预调用

2016-05-31 16:10:14,552 [http-bio-8080-exec-1] [] 警告 o.a.c.p.PhaseInterceptorChain - 跳过拦截器 com.MyInterceptor$$EnhancerBySpringCGLIB$$1afa70e1:阶段声明 不见了。

这是拦截 jaxws 服务器调用。同样,我所做的所有导致问题的更改都是更新到最新版本的 Spring。看起来好像 cxf 正在使用一个从未从 bean 生成的单独拦截器。

编辑

我相信我已经找到了问题所在,但我再次不确定要解决的问题。 Spring 4 代理在创建代理时不会调用构造函数两次(即它使用构造函数创建原始 bean,但 bean 的 CGLIB 创建的代理不调用构造函数)。这会导致拦截器的相位为空。

我在课堂上更改了@PostContsruct 以确认这一点:

    @PostConstruct
public void display() {
    logger.warn(this.getPhase());
    MyInterceptor myInterceptor = (MyInterceptor) appContext.getBean("contentInInterceptor");
    logger.warn("Bean phase is: " + myInterceptor.getPhase());
}

日志显示 bean 创建阶段与代理阶段:

2016-06-01 10:36:52,829 [localhost-startStop-1] [] WARN c.MyInterceptor - 预调用

2016-06-01 10:36:52,839 [localhost-startStop-1] [] WARN c.MyInterceptor - Bean 阶段为:null

【问题讨论】:

  • 感谢这篇文章,因为我今天遇到了同样的问题。 8小时后,实现了自己的IN拦截器,没有扩展AbstractPhaseInterceptor,拦截器终于又被调用了。对于其他人来说,这个问题是在从 spring 3.2.x 迁移到 5.1.x 之后出现的 PS:我为这条消息道歉(而不是评论),但我还没有所需的声誉。

标签: spring cxf objenesis


【解决方案1】:

好的,我现在想出了一个解决方法,但这不是最好的实现。

基本上我最终要做的是创建一个实现 PhaseInterceptor 的抽象类,并且所有这些实现的方法都设置为抽象。

然后我的拦截器从该类扩展,并有自己的阶段/id/before/after 变量。当变量在 bean 的直接类中不可用时,似乎 Spring 的 bean 代理设置可能存在问题。至少这就是我在这种情况下的发现。

同样,不确定这是否是最佳解决方案,但这会使拦截器再次工作。

【讨论】:

    【解决方案2】:

    您说拦截器正在拦截 jaxws 服务器调用。所以我的假设是,它是拨出电话。

    Phase.PRE_INVOKE 用于传入消息。使用 Phase.PRE_STREAM 等其他阶段作为传出消息

    有关阶段的文档,请参阅

    http://cxf.apache.org/docs/interceptors.html

    【讨论】:

    • 抱歉有任何混淆。我的应用程序有一个 jaxws 服务器。我通过 SoapUI 调用服务器,所以消息是入站的。