`

Ejb3开发

    博客分类:
  • Ejb
ejb 
阅读更多

1.开发无状态会话Bean的步骤。
a.开发接口类,并提供业务方法。
b.开发实现类,并实现业务方法。
c.使用@Stateless注解,声明实现类是一个无状态会话Bean。
4.使用@Remote(接口类.class),声明接口为一个远程借口。(默认为本地接口)。//此步骤可省略。

 

接口HelloWorld.java:

packagecom.qcd.ejb3;

publicinterfaceHelloWorld{
publicStringsayHello(Stringname);
}

 

实现类HelloWorldBean.java:

packagecom.qcd.ejb3.impl;

importjavax.ejb.Remote;
importjavax.ejb.Stateless;

importcom.qcd.ejb3.HelloWorld;

@Stateless//声明HelloWorldBean为一个无状态会话Bean。
@Remote(HelloWorld.class)//声明HelloWorld为一个远程借口,默认是本地借口
publicclassHelloWorldBeanimplementsHelloWorld{

@Override
publicStringsayHello(Stringname){
returnname+"says:helloworld!";
}

}

 

2.发布EJB
a.讲EJB打成Jar(可以使用Eclipse的export命令,导出Jar包。也可以用Ant生成Jar包。)
b.复制JAR到发布目录(JBoss默认启动模式是default,那么复制Jar到%JBoss_home%/server/default/deploy)
c.启动JBoss,JBoss会自动发现并部署EJB。(如果已经启动了JBoss,则JBoss可以热部署)。

 

 

 

 

3.调用EJB
Propertiesprops=newProperties();
props.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
props.put("java.naming.provider.url","localhost:1099");

try{
InitialContextic=newInitialContext(props);
HelloWorldhelloworld=(HelloWorld)ic.lookup("HelloWorldBean/remote");
System.out.println(helloworld.sayHello("张三"));
}catch(NamingExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}

java.naming.factory.initial:即Context.INITIAL_CONTEXT_FACTORY,制定JNDI连接工厂。
java.naming.provider.url:即Context.PROVIDER_URL,制定JNDI连接字符串。

调用服务器不同,连接工厂和连接字符串也不同。
Jboss的:
java.naming.factory.initial:org.jnp.interfaces.NamingContextFactory
java.naming.provider.url:localhost:1099

WebLogic的:
java.naming.factory.initial:org.weblogic.jndi.WLInitialContextFactory
java.naming.provider.url:t3://localhost:7001

客户端程序可以部署到另外的计算机上,只需要更改连接的服务器IP地址和启动JBoss绑定相应IP地址即可。
这正是EJB的远程调用特性。
上面代码中返回的HelloWorld对象并不是我们在服务器端编写的HelloWorldBean,而是一个实现了HelloWorld借口的代理对象。
这个代理对象最终调用我们的实现类HelloWorldBean.
helloworld.getClass().getName()可以得到此代理类的类名。

HelloWorldBean/remote:Jndi名称。
讲EJB应用打成Jar包后,默认的全局JNDI名称是:
本地接口:ejb-class-name/local;
远程接口:ejb-class-name/remote;
例如:讲HelloWorld应用打包成Jar,那么它的远程接口的JNDI名称是:HelloWorldBean/remote.

如果讲EJB打包成EAR,默认的全局JNDI名称为:
本地接口:ear-file-base-name/ejb-class-name/local;
远程接口:ear-file-base-name/ejb-class-name/remote;
如讲HelloWorld应用作为模块打包成EARHelloWorld.ear,它的远程接口为:HelloWorld/HelloWorldBean/remote。


除了硬编码制定Context环境外,还可以在类路径新建jndi.properties,讲配置信息写入jndi.properties。
在构造Context时,会自动在类路径查找jndi.properties,并将配置信息加载。
/src/jndi.properties:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099

try{
InitialContextic=newInitialContext();
HelloWorldhelloworld=(HelloWorld)ic.lookup("HelloWorldBean/remote");
System.out.println(helloworld.sayHello("lisi"));
System.out.println(helloworld.getClass().getName());
}catch(NamingExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}

4.使用Ant提高工作效率

<?xmlversion="1.0"encoding="utf-8"?>
<projectbasedir="."name="HelloWorldEjb3">
<propertyname="src.dir"value="${basedir}/src">
</property>
<propertyenvironment="env">
</property>
<propertyname="jboss.home"value="${env.JBOSS_HOME}">
</property>
<propertyname="jboss.server.config"value="default">
</property>
<propertyname="build.dir"value="${basedir}/build">
</property>

<pathid="build.classpath">
<filesetdir="${jboss.home}/client">
<includename="*.jar"/>
</fileset>
<!--将build作为classpath的一部分。-->
<pathelementlocation="${build.dir}"/>
</path>

<targetname="prepare">
<deletedir="${build.dir}">
</delete>
<mkdirdir="${build.dir}"/>
</target>

<!--在编译Java文件之前,先创建文件夹build-->
<targetname="compile"depends="prepare">
<!--将编译后的class文件放到build目录-->
<javacsrcdir="${src.dir}"destdir="${build.dir}"includeantruntime="on">
<classpathrefid="build.classpath">
</classpath>
</javac>
</target>

<targetname="ejbjar"depends="compile"description="创建EJB发布包">
<jardestfile="${basedir}/${ant.project.name}.jar">
<filesetdir="${build.dir}">
<includename="**/*.class"/>
</fileset>
</jar>
</target>

<targetname="deploy"depends="ejbjar"description="发布EJB">
<copyfile="${basedir}/${ant.project.name}.jar"todir="${jboss.home}/server/${jboss.server.config}/deploy">
</copy>
</target>

<targetname="undeploy"description="卸载EJB">
<deletefile="${jboss.home}/server/${jboss.server.config}/deploy/${ant.project.name}.jar">
</delete>
</target>
</project>

 

在执行Ant任务时遇到2个问题:

1.warning:'includeantruntime'wasnotset,defaultingtobuild.sysclasspath=last;settofalseforrepeatablebuilds

解决办法:将
<javacsrcdir="${src.dir}"destdir="${build.dir}">

改为:

<javacsrcdir="${src.dir}"destdir="${build.dir}"includeantruntime="on">

 

2.Unabletofindajavaccompiler;
com.sun.tools.javac.Mainisnotontheclasspath.
PerhapsJAVA_HOMEdoesnotpointtotheJDK.
Itiscurrentlysetto"C:\ProgramFiles\Java\jre6"。

解决办法:将C:\ProgramFiles\Java\jdk1.6.0_22\lib\tools.jar复制到C:\ProgramFiles\Java\jre6\lib。

 

5.远程接口调用Ejb的过程

 

 

 

a.客户端与Ejb建立Socket通信

b.客户端与Ejb在通信管道上发送IIOP协议消息。

那么在此过程中,必然产生网络通信开销、协议解析开销、对象序列化开销等。

但是如果客户端与Ejb在同一机器的同一JVM内,那么它们完全可以通过内存交互,这样就避免了上面因网络通信产生的各种开销。

此时,就可以使用本地接口。

 

6.本地接口的开发

跟远程接口差不多,只需要将@remote改为@local即可。

调用的时候也不需要指明上下文环境信息。

HelloWorldBean.java:

packagecom.qcd.ejb3.impl;

importjavax.ejb.Local;
importjavax.ejb.Remote;
importjavax.ejb.Stateless;

importcom.qcd.ejb3.HelloWorld;

@Stateless//声明HelloWorldBean为一个无状态会话Bean。
//@Remote(HelloWorld.class)//声明HelloWorld为一个远程借口,默认是本地借口
@Local(HelloWorld.class)//指明为本地接口。
publicclassHelloWorldBeanimplementsHelloWorld{

@Override
publicStringsayHello(Stringname){
returnname+"says:helloworld!";
}

}

 

新建Web工程,进行测试

Test.jsp:

<import="com.qcd.ejb3.HelloWorld"%>
<import="javax.naming.NamingException"%>
<import="javax.naming.InitialContext"%>
<import="java.util.Properties"%>
<%@pagelanguage="java"contentType="text/html;charset=UTF-8"
pageEncoding="ISO-8859-1"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=UTF-8">
<title>TestEjbLocalInterface</title>
</head>
<body>
<%
try{
InitialContextic=newInitialContext();
HelloWorldhelloworld=(HelloWorld)ic.lookup("HelloWorldBean/local");
out.println(helloworld.sayHello("lisi"));
System.out.println(helloworld.getClass().getName());
}catch(NamingExceptione){
//TODOAuto-generatedcatchblock
out.println(e.getLocalizedMessage());
}
%>
</body>
</html>

 

测试:

 

 

 

不需要将接口类放入Web的classpath,将ejb应用引入到web工程即可。

 

在实际开发中,会充分考虑到本地调用和远程调用的情况。

因此,一般会有一个远程接口,一个本地接口,本地接口继续远程接口。

实现类同时实现本地接口和远程接口的所有业务方法。

将本地接口类指明为本地接口,远程接口类指明为远程接口。

远程接口HelloWorld.java:

packagecom.qcd.ejb3;

publicinterfaceHelloWorld{
publicStringsayHello(Stringname);
}

 

本地接口HelloWorldLocal.java:

packagecom.qcd.ejb3;

publicinterfaceHelloWorldLocalextendsHelloWorld{
}

 

实现类HelloWorldBean.java:

packagecom.qcd.ejb3.impl;

importjavax.ejb.Local;
importjavax.ejb.Remote;
importjavax.ejb.Stateless;

importcom.qcd.ejb3.HelloWorld;
importcom.qcd.ejb3.HelloWorldLocal;

@Stateless//声明HelloWorldBean为一个无状态会话Bean。
@Remote(HelloWorld.class)//指明HelloWorld为远程接口
@Local(HelloWorldLocal.class)//指明HelloWorldLocal为本地接口。
publicclassHelloWorldBeanimplementsHelloWorld,HelloWorldLocal{

@Override
publicStringsayHello(Stringname){
returnname+"says:helloworld!";
}

}

 

这样的话,不管是本地调用还是远程调用都是OK的。

 

将JBossServer集成到Eclipse中,启动JBoss报如下错误:

原因是AttachmentStore初始化错误。
打开jboss-5.1.0.GA/server/default/conf/bootstrap下的profile.xml文件。

关于AttachmentStore的配置
<!--Theattachmentstore-->
<beanname="AttachmentStore"class="org.jboss.system.server.profileservice.repository.AbstractAttachmentStore">
<constructor><parameter><injectbean="BootstrapProfileFactory"property="attachmentStoreRoot"/></parameter></constructor>

改成
<!--Theattachmentstore-->
<beanname="AttachmentStore"class="org.jboss.system.server.profileservice.repository.AbstractAttachmentStore">
<constructor><parameterclass="java.io.File"><injectbean="BootstrapProfileFactory"property="attachmentStoreRoot"/></parameter></constructor>

 

 

启动JBoss时报如下错误:

[Naming]Couldnotstartonport1099

 

解决办法:

修改\server\default\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml

<!--NamingService-->
<beanclass="org.jboss.services.binding.ServiceBindingMetadata">
<propertyname="serviceName">jboss:service=Naming</property>
<propertyname="bindingName">Port</property>
<propertyname="port">1099</property>
<propertyname="description">ThelisteningsocketfortheNamingservice</property>
</bean>

j将端口1099修改为其他即可。

 

 

7.Ejb调用其他Ejb

我们再创建一个具有本地接口的无状态会话Bean。

在HelloWorldBean中调用这个Bean。

 

本地接口DateUtil.java:

packagecom.qcd.ejb3;

publicinterfaceDateUtil{
publicStringgetSystemTime();
}

 

本地接口实现类DateUtilBean.java:

packagecom.qcd.ejb3.impl;

importjava.text.SimpleDateFormat;
importjava.util.Date;

importjavax.ejb.Stateless;

importcom.qcd.ejb3.DateUtil;
@Stateless
publicclassDateUtilBeanimplementsDateUtil{

/**
*获取当前系统时间。
*/
publicStringgetSystemTime(){
//TODOAuto-generatedmethodstub
SimpleDateFormatsdf=newSimpleDateFormat("yyyy-mm-ddHH:MM:ss");
Datedate=newDate();
returnsdf.format(date);
}

}

 

HelloWorldBean.java:

packagecom.qcd.ejb3.impl;

importjavax.ejb.Local;
importjavax.ejb.Remote;
importjavax.ejb.Stateful;
importjavax.ejb.Stateless;
importjavax.naming.InitialContext;
importjavax.naming.NamingException;

importcom.qcd.ejb3.DateUtil;
importcom.qcd.ejb3.HelloWorld;
importcom.qcd.ejb3.HelloWorldLocal;

//在HelloWorldBean中调用DateUtilBean
//第一种方式,是使用jndi查找DateUtilBean.
//第二种房事,是使用依赖注入。

//@Stateless//声明HelloWorldBean为一个无状态会话Bean。
@Stateful
//@Remote(HelloWorld.class)//声明HelloWorld为一个远程借口,默认是本地借口
@Remote(HelloWorld.class)//指明HelloWorld为远程接口
@Local(HelloWorldLocal.class)//指明HelloWorldLocal为本地接口。
publicclassHelloWorldBeanimplementsHelloWorld,HelloWorldLocal{

@Override
publicStringsayHello(Stringname){
try{
InitialContextic=newInitialContext();
DateUtildu=(DateUtil)ic.lookup("/DateUtilBean/local");
Stringtime=du.getSystemTime();
returnname+"说:现在时间是:"+time;
}catch(NamingExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}

returnnull;
}

}

 

用的是JNDI查找的方式。

 

第二种方式是使用依赖注入。

//使用依赖注入获取Bean
@EJB
privateDateUtildateUtil;

@Override
publicStringsayHello(Stringname){
Stringtime=dateUtil.getSystemTime();
returnname+"说:现在时间是:"+time;
}

 

 

使用@EJB,如果EJB发现有多个实现类时,EJB会报一个异常。
因此,在使用@EJB注解时,通过beanName指定EJB的名称。
如:
@EJB(beanName="DateUtilBean")
privateDateUtildu;

对于定时服务,数据源等,要使用@Resource注解。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics