Java
EJB3入门(3)本地接口
by Elton on 六.16, 2009, under Java
之前用到的都是远程接口,顾名思义,远程接口就是提供不再同一个虚拟机中的两端程序来访问的。适合于分布式部署。但是有的时候客户端和服务端又在一个jvm中,比如在一个tomcat或者jboss的web容器中。这个时候就没有必要用远程接口了,毕竟浪费资源。可以改用local接口。
如果你尝试将上一节中的remote直接替换成local,再执行客户端,你会发现如下错误:
1 | Could not find InvokerLocator URL at JNDI address "ShoppingCartBean/local"; looking up local Proxy from Remote JVM? |
这说明你试图通过远程的jvm来调用本地的端口,因为客户端执行的这个jvm与ejb容器的jvm是两个不同的虚拟机。所以本地接口调用会失败。
在这里我们再建立一个web工程,创建web工程的时候,可以顺便创建一个EAR工程。
然后在这个web工程中加入对之前shoppingcart项目的引用。注意,这里已经将shoppingcart项目中的接口改为local方式。
在Java build path中,点击projects标签,点击add按钮,加入shoppingcart的项目
之后,在web项目中新建一个jsp页面,如index.jsp,代码如下:
1 |
之后就可以将EAR项目导出到jboss的部署目录中了。
部署好以后,jboss的输出会提示:
1 | 19:26:53,132 INFO [TomcatDeployment] deploy, ctxPath=/EJBWeb |
之后就可以在浏览器中输入localhost:8080/EJBWeb来测试本地接口了。
EJB3入门(2)Stateful Session bean
by Elton on 六.16, 2009, under Java
有了上节无状态session bean的基础,这回试着做一个有状态的session bean。 有状态的session bean语法上跟无状态session bean只有一个元标记的区别,把实现类里面的@Stateless替换成@Stateful就可以了。
如果使用Stateful Sessionbean,客户端在使用同一个SessionBean对象实例时可以保存状态,也就是说,在多次引用该对象时实际上在服务端是使用的同一个Sessionbean的对象实例,而无状态sessionbean使用了不同的sessionbean对象实例,因此,是无法保存状态的。
最直接的例子就是购物车,购物车是跟着用户来的,需要保持状态,否则人家挑好的东西都不见了。
先写一个接口:
1 2 3 4 5 6 7 8 9 10 11 | package me.prosight; import java.util.List; import javax.ejb.Remote; @Remote public interface ShoppingCartRemote { public void addProduct(String name); public List<string> getAllProducts(); } |
再写一个实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package me.prosight; import java.util.ArrayList; import java.util.List; import javax.ejb.Stateful; @Stateful public class ShoppingCartBean implements ShoppingCartRemote { private List<string> shoppingCart = new ArrayList<string>(); @Override public void addProduct(String name) { shoppingCart.add(name); } @Override public List<string> getAllProducts() { return shoppingCart; } } |
最后再写一个测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package me.prosight; import java.util.List; import javax.naming.InitialContext; import javax.naming.NamingException; public class Client { public static void main(String[] args) throws NamingException { InitialContext ctx = new InitialContext(); ShoppingCartRemote cart = (ShoppingCartRemote) ctx.lookup("ShoppingCartBean/remote"); cart.addProduct("Apple"); cart.addProduct("IBM"); cart.addProduct("Dell"); List<string> products = cart.getAllProducts(); for (String product : products) { System.out.println(product); } } } |
在客户端调用时,需要将ShoppingCart接口复制到客户端,当然,@Remote可以去掉。别忘了引用JBoss安装目录中的client目录中的jar文件。客户端仍然使用了jndi.properties文件来配置相应的信息,该文件位于源代码目录下,内容如下;
1 2 | java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.provider.url=localhost |
在执行上面的程序后,将输出如下的信息:
1 2 3 | Apple IBM Dell |
要注意的是,需要使用同一个sessionbean对象实例(cart)才能保存状态。如果在web应用程序中,需要将cart对象保存在Session中,这样在同一个会话中的用户就可以使用该购物车对象了。
EJB3入门(1)Stateless Session bean
by Elton on 六.13, 2009, under Java
一直想学EJB,今天有空开始学习。
下载相关资源
JDK 1.6u14 http://java.sun.com
eclipse 3.4 http://www.eclipse.org
Jboss tools http://jboss.org/tools
Jboss AS 5.1.0AS http://www.jboss.org/jbossas
安装配置好后,我们开始写第一个EJB, 先写个无状态的Session Bean — Hello world
先定义接口
1 2 3 4 5 6 7 8 | package me.prosight; import javax.ejb.Remote; @Remote public interface HelloRemote { public String sayHello(String name); } |
再定义实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package me.prosight; import javax.ejb.Stateless; /** * Session Bean implementation class Hello */ @Stateless public class HelloBean implements HelloRemote { @Override public String sayHello(String name) { return "Hello " + name; } } |
启动Jboss服务器,将刚刚的EJB应用部署到jboss中。右键点击项目名称,然后选择Export–>EJB/JAR file

EJB项目部署
将这个Jar包部署到/server/default/deploy中,一会jboss就会自动将这个应用部署到jboss的容器中,后面我们就可以使用这个ejb了。
再写一个测试客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package me.prosight; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public class HelloClent { public static void main(String[] args) throws NamingException { Context ctx = new InitialContext(); HelloRemote hello = (HelloRemote) ctx.lookup("HelloBean/remote"); String msg = hello.sayHello("Elton"); System.out.println(msg); } } |
客户端要注意两件事情
- 确保正确设置了JNDI
- 在引用远程的EJB bean的时候,要使用对应的接口来引用而不是实现类。
JNDI是Java命名和目录接口,是用来标记EJB的bean位置的。 如果你的客户端和EJB不在一个JVM中运行,就需要配置JNDI。当你部署好一个EJB的应用,会在控制台中显示出调用这个EJB的所有的JNDI名称,如:
JNDI
在InitialContext的lookup方法中就可以使用这个名称来引用相关的Bean了。
配置JNDI有两个方法,一个就是在源文件目录中建立jndi.properties文件,我的这个文件内容如下:
1 | java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=localhost:1099 |
provide.url指定的是EJB容器的地址和端口,可以使用IP地址来指定你的EJB容器装在哪台服务器上。
或者在程序中以编程的方式来指定,在new InitialContext()前,输入如下代码:
1 2 3 4 5 | Properties props = new Properties(); props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming"); props.setProperty("java.naming.provider.url", "localhost:1099"); InitialContext ctx = new InitialContext(props); |
运行这个程序,将会在控制台中看到:

程序输出
第一个EJB的Hello World就完成了。还很简单吧。






