您的位置:首页 > 其它

EJB远程访问和本地访问方式

2015-09-11 21:37 239 查看
   现在初次接触EJB,对于EJB的技术简介和经典理论,我们这里不详细讲述,今天我们主要介绍EJB中两种访问方式以及在这个demo中遇到的问题和解决方法。

   EJB支持两种客户端的访问,一种是远程客户端访问,以及客户端与其调用的EJB对象不在一个JVM进程中,另外一种就是本地访问,和第一种相反,客户端和EJB对象同在一个JVM进程中。首先我们要知道最基础的知识,远程访问我们通过注解@Remote来定义企业Bean,本地访问,我们通过@Local来定义。在这里关于远程客户端和本地客户端的特点,我们不介绍了,内容很好理解。下面我们用两个时序图来表示这两种调用方式,由此来分析两种不同访问方式的区别:

   远程访问调用方式:



  本地访问调用方式:



   从时序图中可以很明显的看出区别在于本地访问客户端方式中不需要进行序列化和反序列号,只需要直接调用对应的方法即可。对于远程方式采用传值和本地方式采用传址意义不同就在于传值方式,本地客户端访问和远程客户端访问,对象会发生变化,而传地址方式,因为操作对象只需要知道地址,所有不管在什么样客户端访问都可以找到相应的对象,所以对象不会发生变化。

   安装JBoss和开发部署程序这里不详细介绍了,重点放在Demo实现过程中。

首先建立EJB Project项目,开发服务端:

   我们需要编写一个接口和一个实现类:



   注意,我这里有两个接口分别为:UserManager和UserManagerLocal,因为我用的是Jboss-5.5.1-GA,这个版本的JBoss和4.0版本的JBoss的有点不同就在于@Remote和@Local注解不能同时使用,会抛出这种异常:

org.jboss.deployers.spi.DeploymentException: Error deploying Ejb_03.jar: Cannot designate both javax.ejb.Local and javax.ejb.Remote annotations without 'value' attribute on UserManagerBean. [EJBTHREE-1025]

   他的意思就是说,同一个EJB的Bean对象不能有两种不同的访问方式,因为采用远程和本地bean在JNDI查找的过程中都是以同一个名字进行查找的,如果需要有两种访问方式,我们要为其准备一个value值,指定其具体的访问方式,所以我们采用的解决方法就是,多编写一个接口类,指定为local,也就是UserManagerLocal,并且在bean对象中为不同的方式指定具体的类:

package com.bjsxt.ejb;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;

@Stateless
@Remote({UserManager.class})
@Local({UserManagerLocal.class})
public class UserManagerBean implements UserManager,UserManagerLocal {

public void addUser(User user) {
System.out.println("User[username="+user.getUsername()+"]已经被成功保存");
user.setId(10);
}

}

   编写客户端:



   我们在写客户端程序的时候:

import javax.naming.InitialContext;

public class UserManagerClient {

/**
* @param args
* 远程访问必须要序列化,所以用户类要实现Serializable接口
*/
public static void main(String[] args) throws Exception{

InitialContext context=new InitialContext();
UserManager userManager=(UserManager)context.lookup("UserManagerBean/remote");
User user=new User();
user.setUsername("肖红");
user.setPassword("xiaohong");
userManager.addUser(user);
System.out.println("用户信息已经被成功保存,它的ID是:"+user.getId());

}
}

   我们编写本地客户端(ejb_03_webclient):



   在页面中进行调用:

<%
InitialContext context=new InitialContext();
UserManager userManager=(UserManager)context.lookup("UserManagerBean/remote");
User user=new User();
user.setUsername("张三");
user.setPassword("zhangsan");
userManager.addUser(user);
out.println("用户信息已经被成功保存,它的ID是:"+user.getId());
%>

   因为我们采用的远程方式remote,虽然将服务端和本地端部署到同一个JBoss服务器上,也就是用的本地客户端:



   运行程序,然后进行访问:http://localhost:8081/ejb_03_webclient/

   访问结果为:



   采用本地local:

<%
InitialContext context=new InitialContext();
UserManagerLocal   userManagerlocal=(UserManagerLocal)context.lookup("UserManagerBean/local");
User user=new User();
user.setUsername("张三");
user.setPassword("zhangsan");
userManagerlocal.addUser(user);
out.println("用户信息已经被成功保存,它的ID是:"+user.getId());
%>

   访问结果为:



   两者出现的不同,因为虽然我们是在本地客户端进行访问,但是第一种情况我们仍然使用的是远程的访问方式,采用远程访问方式,客户端参数都会序列化。实现序列化接口以后传递是一个具体的值,这样会发生改变,客户端就不会看到原来的对象。而第二种方式是采用的本地访问方式,不需要序列化,我们从客户端传到服务端的是同一个对象,也就是我们传递的是一个地址,可以通过地址找到这个对象然后进行操作。当服务器端改变了id值,客户端会看到这种改变。

   下面分析一下我遇到的问题以及解决方法:

   在这个过程中我遇到了这样一个问题:“java.lang.ClassCastException: $Proxy103 cannot be cast tocom.tgb.ejb.UserManager”:

   这个问题的解决方法就是修改:

G:\TGB\zhongjianjian\jboss-5.0.1.GA\server\default\deployers\jbossweb.deployer\META-INF\ war-deployers-jboss-beans.xml中的UseJBossWebLoader值:

<propertyname="useJBossWebLoader">false</property>将false修改为true,然后重启JBoss,

   另外一个典型的问题就是关于端口号占用,当我们的程序出现这个问题后我们可以查看占用端口号的程序将其关闭释放出端口号,或者修改我们本程序的端口号,我采用的是修改我们本程序的端口号:找到G:\TGB\zhongjianjian\jboss-5.0.1.GA\server\default\deploy\jbossweb.sar\
server.xml文件,修改端口号为8081:

<Connector protocol="HTTP/1.1" port="8081" address="${jboss.bind.address}"
connectionTimeout="20000" redirectPort="8443" />
   port端口号由8080修改为8081。

   虽然解决掉这些问题也用了我很长时间,但是就是在这样的不断磨练中锻炼了自己使用搜索引擎的能力,我们不怕遇到问题,我们喜欢遇到问题,因为这是这样一个一个的问题让我们长了见识,懂了知识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: