user3296533
user3296533

Reputation: 61

Migrating to JBoss 6.1, add spring for cxf

I am porting an application from JBoss 4 to JBoss 6.1 EAP. This application uses cxf with spring. Our client's requirement is that we will not change (or add) modules for jboss.

In the jboss cxf module, there is an optional dependency to spring, but by default there is no spring module. I was wondering:

  1. Am I required to add a spring module to JBoss?
  2. Can I just add the spring jars to my application lib directory?
  3. What's the best and/or easiest way to get this to work?

If I don't create a spring module and add the spring jars to the application lib directory, I get the following error:

09:19:44,203 WARN  [org.jboss.modules] (MSC service thread 1-1) Failed to define class org.apache.cxf.transport.servlet.CXFServlet in Module "org.apache.cxf.impl:main" from local module loader @1f06dc3 (finder: local module finder @1b64e6a (roots: C:\dev\jboss-eap-6.1\modules,C:\dev\jboss-eap-6.1\modules\system\layers\base)): java.lang.LinkageError: Failed to link org/apache/cxf/transport/servlet/CXFServlet (Module "org.apache.cxf.impl:main" from local module loader @1f06dc3 (finder: local module finder @1b64e6a (roots: C:\dev\jboss-eap-6.1\modules,C:\dev\jboss-eap-6.1\modules\system\layers\base)))
  at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:427) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:260) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:75) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.Module.loadModuleClass(Module.java:526) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:188) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:444) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:432) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:399) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:399) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:374) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:119) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316) [rt.jar:1.6.0_17]
  at java.lang.Class.forName0(Native Method) [rt.jar:1.6.0_17]
  at java.lang.Class.forName(Class.java:247) [rt.jar:1.6.0_17]
  at org.jboss.as.server.deployment.reflect.DeploymentClassIndex.classIndex(DeploymentClassIndex.java:54)
  at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.processComponentConfig(InterceptorAnnotationProcessor.java:85) [jboss-as-ee-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
  at org.jboss.as.ee.component.deployers.InterceptorAnnotationProcessor.deploy(InterceptorAnnotationProcessor.java:77) [jboss-as-ee-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
  at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:120)
  at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)
  at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)
  at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_17]
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_17]
  at java.lang.Thread.run(Thread.java:619) [rt.jar:1.6.0_17]
Caused by: java.lang.NoClassDefFoundError: org/springframework/context/ApplicationListener
  at java.lang.ClassLoader.defineClass1(Native Method) [rt.jar:1.6.0_17]
  at java.lang.ClassLoader.defineClass(ClassLoader.java:616) [rt.jar:1.6.0_17]
  at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:344) [jboss-modules.jar:1.2.0.Final-redhat-1]
  at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:422) [jboss-modules.jar:1.2.0.Final-redhat-1]
  ... 22 more

Upvotes: 3

Views: 2130

Answers (1)

superEb
superEb

Reputation: 5673

tl;dr

  1. Only if you want Spring to manage the lifecycle of your JAX-WS endpoint beans, which is no longer necessary.
  2. No, not if you're trying to use Spring-based CXF features directly in your app. Refer to #1, but keep reading...
  3. The easiest way is to let JBossWS manage your JAX-WS endpoints but have them extend SpringBeanAutowiringSupport to integrate with your app's ApplicationContext. Further details below.

Details

I faced the same problem - migrating an app with Spring-managed JAX-WS endpoints to JBoss EAP 6 (AS 7).

The problem is that JBossWS in EAP 6 is a double-edged sword. It makes it very easy to setup JAX-WS endpoints, abstracting away all knowledge of the underlying CXF engine from your app, but it requires you to relinquish some control over those endpoints.

Instead of using CXF's Spring namespace and defining your endpoints as Spring beans sitting behind a single servlet, you should now remove those beans from the Spring context and define each one as a servlet in web.xml (even though they are not actually servlets!).

JBossWS will auto-detect those pseudo-servlets at runtime and will build the necessary CXF infrastructure behind them.

This is all well-and-good, but what if you need to inject some Spring-managed dependencies into your endpoints?

SpringBeanAutowiringSupport to the rescue! Apparently this was the main reason for this class - to integrate Spring IoC with container-managed beans.

Have your endpoints extend this class, and then your dependencies can be injected via @Autowired (or the like).

Note that you should still use ContextLoaderListener as a listener-class in your web.xml to bootstrap your Spring ApplicationContext.

Note also that your app can now be totally agnostic of CXF - meaning you should not do any of the following:

  • extend or use any CXF classes directly
  • reference any CXF-provided Spring context files (e.g. classpath:META-INF/cxf/cxf.xml)
  • use any CXF namespace in your app's Spring config (e.g. xmlns:jaxws="http://cxf.apache.org/jaxws")

The downside is that your app can no longer use any advanced CXF-specific features, but hopefully this isn't necessary anyway.

Upvotes: 2

Related Questions