今天写了一个Session Bean调用的Demo,可是总是报错 java.lang.ClassCastException: $Proxy91,郁闷至极,删掉整个项目重新写,可是问题依然存在。原来EJB接口Jar文件,我放在client项目的web-info/lib目录 下了,并且EJB接口jar文件和client同时发布到jboss下, 在调用 Stateful Bean 就会发生类型冲突。总结一下整理给大家,希望有帮助。
当你的 EJB3 是 deploy to jboss 的情况下, EJB client 调用 EJB3 分两种情况:
1) 发布在 jboss 的 web app 作为 client 来调用 EJB
EJB 和调用 EJB 的 WEB 应用都发布在 Jboss 集成环境下。在 Jboss 下发布 WEB 应用,需要把 WEB 应用打包成 war 文件。另外在此环境下调用 EJB 不需要把 EJB 的接口类放入 /WEB-INF/classes/ 目录中,否则在调用 Stateful Bean 就会发生类型冲突,引发下面的例外
java.lang.ClassCastException: $Proxy84
org.apache.jsp.StatefulBeanTest_jsp._jspService(org.apache.jsp.StatefulBeanTest_jsp:55)
如果 EJB 和调用 EJB 的 WEB 应用都发布在 Jboss 集成环境下,那么 EJB 的 Local 或 Remote 接口都可以被调用
发布在 Jboss 下的客户端不需要明确设置 JNDI 访问的上下文环境,可以直接通过
InitialContext ctx = new InitialContext()
获得上下文环境,容器会自动赋给 InitialContext 正确的环境,例如:
InitialContext ctx = new InitialContext();// 客户端和 jboss 运行在同一个 jvm, 不需要传入 props
HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");
如果硬给 InitialContext 设置了访问属性,反而会带来不可移植的问题,因为你的应用有可能部署在 weblogic 等应用服务器。(本教程考虑到部分同学可能需要在独立的 J2se 中调用 EJB ,为了教学的方便,把访问属性都设上了,这样不管在 jboss 、 j2se 或独立 tomcat ,都能获得正确的 InitialContext )
2) 在单独的 Tomcat 或 J2SE (如 junit test )中调用 EJB
在正式的生产环境下,大部分调用 EJB 的客户端可能是单独的 Tomcat 或 Resin 。下面介绍如何在单独的 Tomcat 服务器中调用 EJB 。在单独的 Tomcat 服务器中调用 EJB 需要有以下步骤:
A) 把调用 EJB 所依赖的 Jar 包拷贝到 tomcat 下的 /shared/lib 目录或 WEB 应用的 WEB-INF/lib 下 , 所依赖的 Jar 在 jboss 安装目录的 client 目录下。你可以在 eclipse 里设置一个自定义的 library “ ejb3 library ”,把这些 jars 都添加到该 library 里,然后在你的 EJB project 里把“ ejb3 library ” add to classpath
B) 把 EJB 接口拷贝到应用的 /WEB-INF/classes/ 目录下
C) 客户端访问 EJB 时必须明确设置 InitialContext 环境属性,代码如下 :
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
InitialContext ctx = new InitialContext(props);// 客户端和 jboss 运行在同一个 jvm, 不需要传入 props
HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");
Tip: 除了上面通过硬编码设置环境属性的方式外,还可以在应用的 classpath 下放置一个 jndi.properties 文件
注意:在单独的 tomcat 和 J2SE 里不能调用 EJB 的 Local 接口,因为他与 JBOSS 不在同一个 VM 中。 J2se 中调用 EJB3 同样需要把上述 jar 及 EJB 接口放置在应用的类路径下。