【EJB系列】(二)——JBOSS7中EJB的远程调用和本地调用

来源:互联网 发布:finalcap唱词字幕软件 编辑:程序博客网 时间:2024/05/16 01:01

导读

  因为JBOSS6,7版本在EJB的本地调用和远程调用的写法上不同于之前的版本。所以在本篇文章中将给出代码实例,仅供参考。

环境

MyEclipse10
JBOSS7

理论知识

远程调用(Remote Access)

过程

这里写图片描述

远程客户端

运行在跟EJB不同的机器或不同的JVM进程上
它可以是Web组件(如:JSP、Servlet)、应用客户端或其他的EJB
对客户端来说,EJB的位置时透明的。
为了创建一个能够被远程客户端访问的EJB,你必须用@Remote注解来定义这些EJB。

参数传递方式

传值


原因:

这里写图片描述

因为客户端和服务端属于不同的进程,所以内存空间不能共享。
客户端的User对象经过序列化和反序列化之后,变成了服务端的另一个User对象,当服务端对User对象的某个属性进行修改后,客户端的User对象的该属性是没有变化的。在后面的代码中我们会体现这一点。

注意事项

传递的参数如果是对象的话,需要实现序列化的接口implements Serializable

本地调用

过程

这里写图片描述

本地客户端

与EJB运行在同一个JVM进程上
它可以是Web组件(如:JSP、Servlet)或其他的EJB
对客户端来说,EJB的位置时透明的。
为了创建一个能够被远程客户端访问的EJB,你必须用@Local注解来定义这些EJB。

参数传递方式

传址


原因:传递的是对象的引用,不论是客户端或者是服务端对对象进行修改,都修改的是同一份。

代码

EJB的接口和实现

不同于之前的JBOSS版本,这里的EJB不能同时被声明为@Remote和@Local

项目目录

这里写图片描述

User.java(一定要实现Serializable接口)

package com.tgb.ejb;import java.io.Serializable;@SuppressWarnings("serial")public class User implements Serializable {    private String username;    private int id;    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }}

UserManagerRemote.java(远程调用接口)

package com.tgb.ejb;public interface UserManagerRemote {    public void addUser(User user);}

UserManagerLocal.java(本地调用接口)

package com.tgb.ejb;public interface UserManagerLocal {    public void addUser(User user);}

UserManagerBean.java(实现)

package com.tgb.ejb;import javax.ejb.Local;import javax.ejb.Remote;import javax.ejb.Stateless;@Stateless@Local(UserManagerLocal.class)@Remote(UserManagerRemote.class)public class UserManagerBean implements UserManagerRemote,UserManagerLocal {    @Override    public void addUser(User user) {        System.out.println("user.username="+user.getUsername());        user.setId(9);    }}

写完之后记得要部署到JBOSS,并运行JBOSS。

远程调用

常见一个JavaProject

这里写图片描述

具体步骤参考上一篇博文【EJB系列】(一)——JBOSS7中开发一个简单的EJB应用

结果

这里写图片描述

尽管服务端执行了setId(9),但是客户端getId()得到的仍是0。

本地调用

创建Web Project

编写并配置Servlet

UserServlet.java

package com.tgb.web;import java.io.IOException;import java.io.PrintWriter;import java.util.Hashtable;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.tgb.ejb.User;import com.tgb.ejb.UserManagerLocal;@SuppressWarnings("serial")public class UserServlet extends HttpServlet {    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {          response.setContentType("text/html");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        out.print("    This is ");        out.print(this.getClass());        out.println(", using the GET method");        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }}

web.xml

<servlet>       <servlet-name>UserServlet</servlet-name>    <servlet-class>com.tgb.web.UserServlet</servlet-class>  </servlet>  <servlet-mapping>    <servlet-name>UserServlet</servlet-name>    <url-pattern>/servlet/UserServlet</url-pattern>  </servlet-mapping>

部署项目访问Servlet

我的项目的访问连接时http://localhost:8091/ejb_03_webclient/servlet/UserServlet

项目的端口号要根据JBOSS的配置文件standalone.xml来

这里写图片描述

打包jar文件到lib目录下

将EJB项目“ejb_03”的四个java文件导出成jar包并且添加到此项目的WEB-INF的lib路径下

这里写图片描述

编写客户端

final Hashtable jndiProperties = new Hashtable();               jndiProperties.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");//让JNDI API知道是由谁来管理我们用来查找JNDI 名字的命名空间的。        Context context;        try {            context = new InitialContext(jndiProperties);            //appName 和 moduleName分别就打包的格式而定            //如果是.ear就是appName,其它的是moduleName(.jar,.war)            final String appName = "";            final String moduleName = "ejb_03_webclient";            final String distinctName = "";            //实现类名            final String beanName = "UserManagerBean";            System.out.println(beanName);            //接口类名            final String viewClassName = UserManagerLocal.class.getName();            System.out.println(viewClassName);            String jndi = "java:module/" + beanName + "!" + viewClassName;            System.out.println(jndi);            UserManagerLocal userManagerLocal;              userManagerLocal = (UserManagerLocal) context.lookup(jndi);                     User user=new User();            user.setUsername("许晨阳");                        userManagerLocal.addUser(user);            System.out.println("用户id:"+user.getId());        } catch (NamingException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }

运行JBOSS

通过控制台我们可以看到我们部署后的EJB在JNDI中的路径,上面的代码中我们用的是其中的一个路径,剩余的这两个也可以:

java:global/ejb_03_webclient/UserManagerBean!com.tgb.ejb.UserManagerLocaljava:app/ejb_03_webclient/UserManagerBean!com.tgb.ejb.UserManagerLocal

这里写图片描述

这里写图片描述

我们看到最后输入的用户id为9,说明服务端的改变,用户端可以看到,说明操作的是同一个User对象。

总结

在这个过程中遇到的问题,包括:

1.本地调用时不需要引入jboss-client.jar,也不需要配置jboss-ejb-client.properties,但是要引入ejb_03.jar,而且要放到lib目录中,否则会报ClassDefNotFound,ClassCastException等错误。
2.另一个就是context.lookup时传递的名称。

远程调用的时候是:

String jndi = "ejb:" + appName + "/" + moduleName + "/"                + distinctName + "/" + beanName + "!" + viewClassName;

本地调用的时候:

去掉前面的”ejb:”。换成“java:global”或“java:app”或“java:module”,但是要注意moduleName为ejb_03_webclient而不是“ejb_03”。具体路径的拼接,参考我们控制台输出的那三条路径,稍有不同。

参考

JNDI Reference
[AS7.1.1] EJB JNDI Lookup confusion: remote vs local

0 0
原创粉丝点击