在EJB编程中可以将EJB发布成远程的访问方式和本地的访问方式,那么什么是本地访问方式,什么又是远程访问方式?准确的来讲,区分本地还是远程关键要看EJB和客户端是否在同一个JVM中。如果我们的ejb和客户端同时部署在这个jvm中,当客户端访问ejb的时候我们就认为是本地访问,否则则是远程访问。那么远程访问和本地访问有什么区别呢?
首先第一点来讲本地访问和远程访问在性能上是有很大的差别的,本地方式调用EJB传的是地址,访问速度相比远程访问来讲要快的多,客户端看到的对象和服务器端是同一个,客户端能够看到服务器端的改变,传递的参数不需要事先序列化接口。而远程调用的方式较慢,因为要建立socket连接,需要对传输的参数进行序列化和反序列化,所以在使用远程调用的时候尽量减少方法的调用,尽量使用粗粒度的接口,并尽量在一次方法调用中传输完所需要的数据。
第二点来讲选择远程访问方式还是本地访问方式并不是我们可以随意决定的,因为对于本地客户端来讲,EJB无论发布成远程接口还是本地接口都是可以访问的(这里需要注意的的是,将EJB发布成远程访问,即便客户端和EJB在同一个JVM中,会仍然按照实际的远程访问方式进行访问,其各种性能与真正的远程访问是一致的),而如果将EJB发布成远程访问方式,只能访问远程接口不能访问本地接口。
下面我们通过一个小例子来说明一下远程调用和本地调用的整个过程,首先来看EJB:
@Stateless
@Remote
public class UserManagerBean implements UserManager {
public void addUser(User user) {
System.out.println("User[username=]" + user.getUserName() + "]已经被成功保存");
user.setId(10);
}
}
上面的EJB实现了UserManager接口,其中addUser()中的参数User为一个Pojo类。具一个String类型的属性userName。我将分别用本地客户端和远程客户端分别调用该EJB解析两个调用过程的区别。
1.远程客户端的调用:
public class UserManagerClient {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
//获取上下文对象
InitialContext context = new InitialContext();
//获取远程EJB接口
UserManager userManager = (UserManager)context.lookup("UserManagerBean/remote");
User user = new User();
user.setUserName("张三");
user.setPassword("zhangsan");
//调用远程EJB方法
userManager.addUser(user);
System.out.println("用户信息已被成功保存,他的ID是:"+ user.getId());
}
}
执行该远程客户端我们可以看到输出结果为:用户信息已被成功保存,他的ID是:0,这也再次验证远程客户端调用传递的参数是值,客户端拥有的只是EJB的一个拷贝。同时需要注意的是User对象一定要实现序列化接口,否则无法进行传递。他的调用过程可以用下面这个图来表示:
2.本地客户端调用与远程客户端调用相比EJB,可以发不成Local方式,也可以发布成Remote,另外EJB中addUser()方法的参数User类可以不实现序列化接口。在本例中我将EJB的发布方式改为Local方式,下面来看客户端的具体代码:
<%@ page language="java" import="java.util.*,javax.naming.*,com.bjsxt.ejb.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
InitialContext context = new InitialContext();
UserManager userManager = (UserManager)context.lookup("UserManagerBean/local");
User user = new User();
user.setUserName("张三");
user.setPassword("zhangsan");
userManager.addUser(user);
out.println("用户信息已被成功保存,他的ID是:"+ user.getId());
%>
</body>
</html>
通过一个java web项目作为本地客户端调用ejb,当我们访问web项目的index.jsp界面的时候会发现其输出为:用户信息已被成功保存,他的ID是:10,这说明,通过Local方式调用EJB,传递方式是传地址,其调用过程可以用下面的图来表示:
对比远程调用和本地调用的过程图,我们可以发现,他们的不同之处就在于是否建立socket连接,对参数进行序列化传输和反序列化操作,也正是由于这个原因使得本地调用的性能要远远的高于远程调用,所以我们在做EJB开发的时候一定要考虑实际情况来决定采用远程客户端调用方式还是本地客户端调用方式。