无状态bean(stateless)使用实例池技术管理bean,在实例池里的bean会被多个用户共用
有状态bean(stateful)使用激活(activation)管理bean,为每个用户创建一个bean,一个bean只为一个用户服务
当一段时间内没用没使用的时候ejb会把该bean的信息序列化到磁盘上,释放内存空间;
当在缓存周期内使用了该bean的时候,ebj自动到磁盘上调用信息还原到内存上(激活)
建立ejb的一般步骤:(远程接口的建立,本地建立相似)
0.建立工程并导入jboss中的EJB jar文件
1.编写接口(HelloWorld)和实现类(HelloWorldBean),在实现类注解其接口类型和状态类型
package huanran.ejb3.bean;
import huanran.ejb3.HelloWorld;
import javax.ejb.Remote;
import javax.ejb.Stateless;
@Stateless
@Remote(HelloWorld.class)
public class HelloWorldBean implements HelloWorld {
4.发布打包,可采用ant组件实现自动打包,详细可查看原程序(build.xml位于工程目录下)
<?xml version="1.0" encoding="utf-8"?>
<project name="RemoteBean">
<!-- properies -->
<property name="basedir" value="." />
<property name="src.dir" value="${basedir}/src" />
<property environment="env"/>
<property name="jboss.home" value="D:/jboss-4.2.3.GA" />
<property name="build.dir" value="${basedir}/build" />
<property name="jboss.server.config" value="default" />
<!-- 定义classpath -->
<path id="build.classpath">
<fileset file="${jboss.home}/client/*.jar">
</fileset>
<pathelement location="${build.dir}" />
</path>
<!-- 初始化任务 -->
<target name="prepare">
<delete dir="${build.dir}"/>
<mkdir dir="${build.dir}"/>
</target>
<!-- 编译 -->
<target name="compile" depends="prepare" description="compile the source files">
<javac srcdir="${src.dir}" destdir="${build.dir}">
<classpath refid="build.classpath" />
</javac>
</target>
<!-- 打包成jar -->
<target name="pack" depends="compile" description="make .jar file">
<jar jarfile="${basedir}/${ant.project.name}.jar">
<fileset dir="${build.dir}">
<include name="**/*.class"/>
</fileset>
</jar>
</target>
<!-- 发布ejb -->
<target name="deploy" depends="pack" description="发布ejb">
<copy file="${basedir}/${ant.project.name}.jar" todir="${jboss.home}/server/${jboss.server.config}/deploy"/>
</target>
<!-- 删除ejb -->
<target name="undeploy" description="删除ejb">
<delete file="${jboss.home}/server/${jboss.server.config}/deploy/${ant.project.name}.jar"/>
</target>
</project>
5.编写客户端,调用接口(这里可选择编写jndi文件或者使用Properties类)
package huanran.test;
import huanran.ejb3.HelloWorld;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class HelloWorldTest {
/**
* @param args
*/
public static void main(String[] args) {
/*Properties p=new Properties();
p.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
p.setProperty("java.naming.provider.url", "localhost:1099");*/
try {
/*InitialContext ic=new InitialContext(p);*/
//有了jdni.properties文件后,就无需Properties
InitialContext ic=new InitialContext();
HelloWorld hwb=(HelloWorld)ic.lookup("HelloWorldBean/remote");
System.out.println(hwb.say("huanran"));
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
本地接口(用Remote注解)和远程接口(Local)
EJB远程调用过程中,会有网络通信开销、协议解析开销、对象序列化开销,如果是本地调用的话,可以编写本地接口bean,从而节省这些开销:
本地bean必须与ejb在同一个jvm中才能调用
疑问:本地或者远程调用ejb时,如果有多个ejb中有相同的bean,那么怎么调用指定的bean(练习中出现ejb调用错乱)
多个EJB 之间的调用,可以采用如下二种方式:
1, jndi注入,如上面例题
2, @EJB注入
@EJB Other other;
/*ejb容器找到实现了Other接口的类,实例化给other,如果存在多个实现了Other的类,必须指定为调用哪个bean,如
@EJB(beanName="OtherBean")Other other1;
*/
public String say(String name) {
// TODO Auto-generated method stub
return name+" say:Hello World!";
}
2.把HelloWorld定义为无状态bean(@Stateless)
3.设置其为远程接口(@Remote)