关于EJB异步调用遇到的问题解决
2017-01-09 15:59
363 查看
近日看到ejb异步调用相关文章,突然有兴趣试下,做个示例程序都是磕磕绊绊的,所幸最后都解决了,在这里记录下遇到的问题和解决版本,希望对大家有所帮助。
异步ejb?
Asynchronous Session BeanEJB 3.1 规范定义可以采用异步的机制,将原本需要长时间执行的工作并行化。无论客户端是本地还是远程的,都可以声明 EJB 的业务方法与客户端异步执行。缺省情况下,业务方法相对于客户端是同步的。
这个新特性主要为了提高性能和可扩展性,允许客户端请求由多个线程 (thread) 处理。客户端可以调用多个异步的 EJB 方法利用多线程并发处理工作,同时客户端线程也能继续处理请求。
有两种方式的异步 EJB 方法调用:
”fire and forget”:声明异步方法返回值为 void,客户端无法知道异步方法调用何时结束。这种方式适用于执行一些“可有可无”、其是否完成无关紧要的场景。通过这种方式的异步请求,主线程上重要操作的性能因此而得到提高。
“fire and return results”:声明异步方法有个 Future 类型的返回参数。该异步方法执行前,会立即先返回一个 Future 实例给应用程序客户端,然后客户端可以用 Future 实例的 get() 方法来检查异步方法完成与否。
示例程序
这里只是为了测试ejb的远程调用,所以示例程序写的比较简单。
远程接口类 RemoteInface.java:
远程接口实现类 RemoteServer.java:
可以看到,异步ejb实现很简单,只需在想异步调用的方法上加上注释 @Asynchronous即可
注: @Asynchronous这个注解是ejb3.1以上提供的,如果编译时找不到这个注解,注意ejb包的版本!!!
客户端测试程序 EjbClient.java—在weblogic11g下测试:
前面几个方法调用都没有问题,但是调用inface1.sayBye1时总报错:
java.io.NotSerializableException: javax.ejb.AsyncResult如下图所示:
可以看出问题主要原因是AsyncResult没有序列化,可是这是ejb3实现类,主要是为了远程调用,序列化的问题不可能没有想到。起初我猜想是不是包的版本太低,后来下了几个包后发现代码没有变化,这时我在一篇文章中看到这么一句话:
注意:javax.ejb.AsyncResult 对象是 Future 的一个简单实现,只用于向容器传送对象,该对象不会被传到客户端。
所以我猜想,可能是容器的问题,我使用的是weblogic11g,可能该版本还没有完全兼容javaee6。也有网友给出了这样的结论
WebLogic 11g is fully Java EE 5 compliant [1], but WebLogic 11gR1 PS3 (10.3.4) included some Java EE 6 technologies [2,3]
所以我决定换个应用服务器验证下,WebLogic 12c已经完成兼容了Java EE 6,但是想到weblogic付费及一系列问题,所以我使用了更轻量级的JBoss来测试,本人第一次使用jboss,有不足之处希望请大家批评指正。
JBoss版本jboss-as-7.1.0.Final(7.0以上完全兼容了Java EE 6)。第一次使用jboss发现果然很简单,这里就不赘述那些安装配置了,在部署好ejb后,继续运行客户端,还是遇到了问题……,这里顺便记录下JBoss调用ejb的过程。
客户端添加代码用来获取上下文:
要注意JBoss5和JBoss6、7调用方法不一样,这里只示例JBoss7使用。
客户端改下:
在客户端引入包:jboss-client-7.1.0.Final.jar(在jboss安装目录/bin/client下),
创建 jboss-ejb-client.properties文件
默认的remote端口是4447。
测试通过,可以通过future.get()取到值。
可能会遇到的问题:
No EJB receiver available for handling [appName:,modulename:myEjbTest,distinctname:] combination
原因1:host和端口没有写对,记得端口是远程端口
原因2:工程中有其它jndi文件,加载时覆盖了jboss-ejb-client.properties文件(可以跟断点查看context内容)
原因3:没有jboss-ejb-client.properties配置文件
异步ejb?
Asynchronous Session BeanEJB 3.1 规范定义可以采用异步的机制,将原本需要长时间执行的工作并行化。无论客户端是本地还是远程的,都可以声明 EJB 的业务方法与客户端异步执行。缺省情况下,业务方法相对于客户端是同步的。
这个新特性主要为了提高性能和可扩展性,允许客户端请求由多个线程 (thread) 处理。客户端可以调用多个异步的 EJB 方法利用多线程并发处理工作,同时客户端线程也能继续处理请求。
有两种方式的异步 EJB 方法调用:
”fire and forget”:声明异步方法返回值为 void,客户端无法知道异步方法调用何时结束。这种方式适用于执行一些“可有可无”、其是否完成无关紧要的场景。通过这种方式的异步请求,主线程上重要操作的性能因此而得到提高。
“fire and return results”:声明异步方法有个 Future 类型的返回参数。该异步方法执行前,会立即先返回一个 Future 实例给应用程序客户端,然后客户端可以用 Future 实例的 get() 方法来检查异步方法完成与否。
示例程序
这里只是为了测试ejb的远程调用,所以示例程序写的比较简单。
远程接口类 RemoteInface.java:
public interface RemoteInface { public String sayHello(String str); public void sayHello1(String str); public void sayBye(String str); public Future<String> sayBye1(String str); }
远程接口实现类 RemoteServer.java:
@Remote @Stateless(mappedName="Remote") public class RemoteServer implements RemoteInface { /* (non-Javadoc) * <p>Title:sayHello</p> * <p>Description:</p> * @param str * @return * @see com.css.sword.ejb.RemoteInface#sayHello(java.lang.String) */ @Override public String sayHello(String str) { // TODO Auto-generated method stub System.out.println("接收到的信息为:"+str+new Date()); return str; } public void sayHello1(String str) { // TODO Auto-generated method stub System.out.println("接收到的信息为:"+str+new Date()); } @Asynchronous public void sayBye(String str) { // TODO Auto-generated method stub System.out.println("接收到的信息为:"+str+new Date()); } @Asynchronous public Future<String> sayBye1(String str) { // TODO Auto-generated method stub System.out.println("接收到的信息为:"+str+new Date()); return new AsyncResult<String>(str); }
可以看到,异步ejb实现很简单,只需在想异步调用的方法上加上注释 @Asynchronous即可
注: @Asynchronous这个注解是ejb3.1以上提供的,如果编译时找不到这个注解,注意ejb包的版本!!!
客户端测试程序 EjbClient.java—在weblogic11g下测试:
public class EjbClient { public static void main(String[] args) throws InterruptedException, ExecutionException{ String connectFactory = "weblogic.jndi.WLInitialContextFactory"; String url = "t3://127.0.0.1:7001"; try { Hashtable<Object,Object> env = new Hashtable<Object,Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, connectFactory); env.put(Context.PROVIDER_URL,url); Context ctx =new InitialContext(env); RemoteInface inface = (RemoteInface) ctx.lookup("Romate.EjbServer"); long startTime = System.currentTimeMillis(); System.out.println(inface.sayHello("你好,世界")); inface.sayHello1("你好,世界"); inface.sayBye("你好,世界"+new Date()); Future<String> futrue=inface1.sayBye1("你好,世界"+new Date()); System.out.println(futrue.get()); long endTime = System.currentTimeMillis(); System.out.println(endTime-startTime); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
前面几个方法调用都没有问题,但是调用inface1.sayBye1时总报错:
java.io.NotSerializableException: javax.ejb.AsyncResult如下图所示:
可以看出问题主要原因是AsyncResult没有序列化,可是这是ejb3实现类,主要是为了远程调用,序列化的问题不可能没有想到。起初我猜想是不是包的版本太低,后来下了几个包后发现代码没有变化,这时我在一篇文章中看到这么一句话:
注意:javax.ejb.AsyncResult 对象是 Future 的一个简单实现,只用于向容器传送对象,该对象不会被传到客户端。
所以我猜想,可能是容器的问题,我使用的是weblogic11g,可能该版本还没有完全兼容javaee6。也有网友给出了这样的结论
WebLogic 11g is fully Java EE 5 compliant [1], but WebLogic 11gR1 PS3 (10.3.4) included some Java EE 6 technologies [2,3]
所以我决定换个应用服务器验证下,WebLogic 12c已经完成兼容了Java EE 6,但是想到weblogic付费及一系列问题,所以我使用了更轻量级的JBoss来测试,本人第一次使用jboss,有不足之处希望请大家批评指正。
JBoss版本jboss-as-7.1.0.Final(7.0以上完全兼容了Java EE 6)。第一次使用jboss发现果然很简单,这里就不赘述那些安装配置了,在部署好ejb后,继续运行客户端,还是遇到了问题……,这里顺便记录下JBoss调用ejb的过程。
客户端添加代码用来获取上下文:
/** * @name:getJboss7Context * @Description: Jboss6、7通过jndi查找ejb的方法和jboss5有点不一样,这里示例的是jboss7 * @author yuanxj * @date 2017-1-9 上午11:01:28 * @param appName 这里是.EAR包的名称,如果你打包成JAR发布的话,这里则留空 * c305 @param moduleName 这里是你发布的JAR文件名(.jar,.war),如helloworld.jar,则这里应该为helloworld。去掉后缀即可 * @param distinctName 如果没有定义其更详细的名称,则这里留空 * @param beanClass 实现类 * @param InterfaceClass 接口类 * @return * @throws NamingException */ private static Map<String,Object> getJboss7Context(String appName,String moduleName,String distinctName,Class beanClass,Class InterfaceClass) throws NamingException{ Map<String,Object> resultMap = new HashMap<String,Object>(); final Hashtable<String, Object> jndiProperties = new Hashtable<String, Object>(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); //jndiProperties.put("jboss.naming.client.ejb.context", true); final Context context = new InitialContext(jndiProperties); final String beanName = beanClass.getSimpleName(); //这里为实现类的名称 final String viewClassName = InterfaceClass.getName(); //这里为你的接口名称 /* * For stateless beans: ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface> For stateful beans: ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>?stateful * */ String jndi = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName; System.out.println("jndi名为:"+jndi); resultMap.put("context", context); resultMap.put("jndi", jndi); return resultMap; }
要注意JBoss5和JBoss6、7调用方法不一样,这里只示例JBoss7使用。
客户端改下:
public static void main(String[] args) throws InterruptedException, ExecutionException{ try { Map<String,Object> jbossMap=getJboss7Context("","myEjbTest","",RemoteServer.class,RemoteInface.class); Context ctx1 = (Context) jbossMap.get("context"); RemoteInface inface1 = (RemoteInface) ctx1.lookup((String)jbossMap.get("jndi")); inface1.sayHello("你好,世界"); inface1.sayHello1("你好,世界"); Future<String> futrue=inface1.sayBye1("你好,世界"+new Date()); System.out.println(futrue.get()); long endTime = System.currentTimeMillis(); System.out.println(endTime-startTime); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
在客户端引入包:jboss-client-7.1.0.Final.jar(在jboss安装目录/bin/client下),
创建 jboss-ejb-client.properties文件
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default remote.connection.default.host=localhost remote.connection.default.port=4447 remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
默认的remote端口是4447。
测试通过,可以通过future.get()取到值。
可能会遇到的问题:
No EJB receiver available for handling [appName:,modulename:myEjbTest,distinctname:] combination
原因1:host和端口没有写对,记得端口是远程端口
原因2:工程中有其它jndi文件,加载时覆盖了jboss-ejb-client.properties文件(可以跟断点查看context内容)
原因3:没有jboss-ejb-client.properties配置文件
相关文章推荐
- 最近在ArcGIS Engine开发中关于调用gp工具过程出现COM 组件的调用返回了错误 HRESULT E_FAIL 错误的解决方法 和 学习oracle中遇到的一些问题总结
- 关于JAVA调用Matlab遇到的问题+JDK重装后原有项目报错的解决办法
- java.lang.Process调用程序阻塞问题解决(刚刚遇到的问题,看有人解决了,转一下:) )
- VS2008中关于“加载安装组件时遇到问题。取消安装”的解决
- 关于在做java的Web开发中遇到跨域访问的问题的解决方法汇总
- VC调用Delphi的DLL时遇到的问题及解决
- jboss客户端调用ejb“Connection refused to host: 127.0.0.1”问题的解决
- linux下安装Subversion遇到关于BerkeleyDB问题及解决方法
- 关于Cookie跨域操作遇到的问题及解决方法
- 遇到动态调用Parameters .AddWithValue()参数类型问题的解决方法
- 关于.net里调用外部CSS失效的问题解决
- SOS!!!关于游戏汉化项目中遇到一些不能解决的问题。。。。。
- VS2008中关于“加载安装组件时遇到问题。取消安装”的解决
- 最近要做个项目,遇到一些关于ansys问题,看看兄弟们能否帮我解决?
- 关于VISTA遇到“Windows需要您的许可才能继续”的问题解决办法
- java 线程遇到的问题及解决方法 JNI调用
- 关于解决在.Net中调用Excel对象后关闭Excel进程的问题
- 关于SQL SERVER 2008安装过程中遇到的个小问题及解决办法
- ::GetDlgItem调用 窗口控件遇到的中断 (自己遇到的问题,已被解决)
- ajax2级联动,遇到一个异步优先级问题,使用settimeout 解决