EJB实例教程笔记(一)

EJB实例教程笔记(一)

电子书EJB3实例教程byLiHuoming.pdf笔记

第一章 EJB知识和运行环境配置
EJB定义了三种企业Bean:会话Bean(Session Bean),实体Bean(Entity Bean)和消息驱动Bean(Message Driven Bean)
消息驱动BEAN(MDB)
使用于业务执行的时间长,执行结果无需实时给用户反馈的场合。

安装JDK1.6,Eclipse3.5,JBOSS5.1
我在eclipse中启动JBOSS5.1,然后通过浏览器访问地址 http://localhost:8080 点击管理控制台Administration Console用户名和密码默认是admin

运行第一个个EJB示例
源码下载地址:http://www.foshanshop.net/download.html

找到helloword目录F:\book\ejb\EJB3实例教程代码示例\sourcecode\HelloWorld,将HelloWorld.jar放到
目录 E:\jboss-5.1.0.GA\server\default\deploy

找到F:\book\ejb\EJB3实例教程代码示例\sourcecode\EJBTest下面的EJBTest.war拷贝到jboss发布目录。

启动JBOSS,访问地址:http://localhost:8080/EJBTest/Test.jsp , 就看到hello world了。呵呵。

JBOSS自动查找deploy目录中的.jar .war .ear,JBOSS通过对比时间戳来检测变化。开始学习示例。

HelloWorld导入eclipse,导入server----jboss等,就去掉了红叉了。启动JBOSS,远程调用HelloWorldBean,运行单元测试HelloWorldTest.java,执行成功。

测试类如下HelloWorldTest.java:
public class HelloWorldTest {
protected static HelloWorld helloworld;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
InitialContext ctx = new InitialContext(props);
helloworld = (HelloWorld)ctx.lookup("HelloWorldBean/remote");
}

@Test
public void testSayHello() {
String result = helloworld.SayHello("佛山人");
//System.out.println(result);
assertEquals("佛山人说:你好!世界,这是我的第一个EJB3哦.", result);
}
}
无状态的会话Bean如下HelloWorldBean.java:
package com.foshanshop.ejb3.impl;

import com.foshanshop.ejb3.HelloWorld;

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

@Stateless
@Remote ({HelloWorld.class})
public class HelloWorldBean implements HelloWorld {
public String SayHello(String name) {
return name +"说:你好!世界,这是我的第一个EJB3哦.";
}
}

第二章 会话Bean(Session Bean)

分为有状态和无状态Bean
有状态BEAN可以维护会话状态,EJB容器要为每个用户创建一个BEAN实例,并通过该实例保存与用户的会话状态;
无状态BEAN,不维护会话状态,BEAN实例不需要保存与某个用户的会话状态,一个BEAN实例可以为多个用户服务。

无状态BEAN,使用对象池技术,少量实例处理多请求。

2.1 Stateless Session Beans(无状态bean)开发

2.1.1 开发只实现Remote接口的无状态Session Bean

示例中调用EJB的JSP代码如下:
<%@ page contentType="text/html; charset=GBK"%>
<%@ page import="com.foshanshop.ejb3.HelloWorld, javax.naming.*, java.util.Properties"%>
<%
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
try {
InitialContext ctx = new InitialContext(props);
HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");
out.println(helloworld.SayHello("佛山人"));
} catch (NamingException e) {
out.println(e.getMessage());
}
%>

@Stateless 无状态会话Bean
@Remote Remote接口
多个接口 @Remote({HelloWorld.class,Hello.class,World.class})

发布了EJB后,可以在这里查看,地址:http://localhost:8080/jmx-console/
里面的JBOSS.J2EE

JNDI名称规则
如果是打成EAR包的,
本地接口:EAR_FILE_BASE_NAME/EJB_CLASS_NAME/local
远程接口:EAR_FILE_BASE_NAME/EJB_CLASS_NAME/remote

EJB应用打包为.jar的模块文件,默认的全局JNDI名称
本地接口:EJB_CLASS_NAME/local
远程接口:EJB_CLASS_NAME/remote

EJB-CLASS-NAME是不带包名的,如果通过@stateless.name() @Stateful.name()指定了EJB名称,那么EJB-CLASS-NAME就要替换为EJB名称。

props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");

java.naming.factory.initial或Context.INITIAL_CONTEXT_FACTORY,环境属性名,用于指定InitialContext工厂(JDNI驱动),类似于JDBC指定数据库驱动类。这里指定JBOSS提供的驱动类:
org.jnp.interfaces.NamingContextFactory

java.naming.provider.url或Context.PROVIDER_URL,环境属性名,包含提供命名服务的主机地址和端口号。类似于JDBC指定数据库的连接URL。连接到JBOSS的格式为:jnp://host:port,其中jnp:是指使用的协议,JBOSS使用的是基于Socket/RMI的协议。

另外还有
java.naming.security.principal or Context.SECURITY_PRINCIPAL
java.naming.credential or Context.SECURITY_CREDENTIALS

避免硬编码,还可以在classpath中加入,jndi.properties文件
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
对于HelloWorld的Bean class,并不要求必须实现HelloWorld接口,可以去掉接口实现,但是一般不推荐这样。按照接口编程约束,接口要引用目标类,那么目标类必须实现接口才可以,否则接口是引用不了实现类的。事实上,EJB客户端接口引用的对象并非Bean类,跟Bean类对象的交互也不是直接进行的,这要看EJB的调用机制,才能得到答案。

2.1.2 开发只实现Local接口的无状态Session Bean
将原有的标签@Remote改为@Local。Local接口的客户端与EJB容器必须在同一个JVM中。

2.1.3 开发实现了Remote与Local接口的无状态Session Bean
我的整个BUILD文件build.xml如下:
<project name="${app.name}" default="all" xmlns:ivy="antlib:org.apache.ivy.ant">
<!-- some variables used -->
<property file="build.properties" />
<property name="app.name" value="${app.name}" />
<property name="src.dir" value="src" />
<property name="conf.dir" value="conf" />
<property name="build.dir" value="build" />
<property name="dist.dir" value="dist" />
<property name="web.dir" value="WebContent" />
<property name="lib.dir" value="${web.dir}/WEB-INF/lib" />
<property name="tomcat.dir" value="${catalina.home}" />
<property name="jboss.dir" value="${jboss.home}" />
<property name="jboss.server" value="${jboss.server.config}" />

<property name="ivy.install.version" value="2.0.0" />
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />

<!-- paths used for compilation and run -->
<path id="compile.path.id">
<fileset dir="${jboss.dir}\client">
<include name="*.jar" />
</fileset>
<fileset dir="${tomcat.dir}\lib" />
<fileset dir="${lib.dir}" />
<path location="${build.dir}" />
</path>

<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar.file}" />
<target name="download-ivy">
<mkdir dir="${ivy.jar.dir}" />
<get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar" dest="${ivy.jar.file}" usetimestamp="true" />
</target>

<!-- ================================= target: resolve ================================= -->
<target name="resolve" depends="download-ivy" description="--> retreive dependencies with ivy">
<ivy:retrieve pattern="${web.dir}/WEB-INF/lib/[artifact]-[revision].[ext]" />
</target>

<!-- ================================= target: clean-cache ================================= -->
<target name="clean-cache-lib" description="--> clean the ivy cache">
<delete dir="${ivy.home}/cache" />
</target>

<!-- ================================= target: clean ================================= -->
<target name="clean" description="--> clean the project">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" />
<delete file="${jboss.dir}\server\${jboss.server}\deploy\${app.name}.jar" />
</target>

<!-- ================================= target: prepare ================================= -->
<target name="prepare" description="--> make-dir build , dist">
<tstamp />
<mkdir dir="${build.dir}" />
<mkdir dir="${dist.dir}" />
<echo message="built at ${DSTAMP}-${TSTAMP}" />
<echo message="ant.version - ${ant.version}" />
<echo message="ant.java.version - ${ant.java.version}" />
<echo message="ivy.cache.dir - ${ivy.home}/cache" />
</target>

<!-- ================================= target: compile ================================= -->
<target name="compile" depends="prepare" description="--> Compile Java sources">
<!-- Compile Java classes as necessary -->
<property name="compile.java.encoding" value="${ant.encoding}" />
<mkdir dir="${build.dir}/WEB-INF/classes" />
<javac srcdir="${src.dir}" destdir="${build.dir}/WEB-INF/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" optimize="${compile.optimize}" encoding="${ant.encoding}" source="${java.level}">
<classpath refid="compile.path.id" />
</javac>
<copy todir="${build.dir}/WEB-INF/classes">
<fileset dir="${src.dir}">
<include name="**/*.xml" />
<include name="**/*.txt" />
<include name="**/*.properties" />
<exclude name="config.properties" />
<exclude name="log4j.properties" />
</fileset>
</copy>
</target>

<!-- ================================= target: javadoc ================================= -->
<target name="javadoc" depends="compile" description="-->Create Javadoc API documentation">
<mkdir dir="${dist.dir}/api-docs" />
<javadoc sourcepath="${src.dir}" destdir="${dist.dir}/api-docs" packagenames="*">
<classpath refid="compile.path.id" />
</javadoc>
</target>

<target name="copyWeb">
<copy todir="${build.dir}">
<fileset dir="${web.dir}">
<exclude name="WEB-INF/classes/**" />
</fileset>
</copy>
</target>

<target name="web.war" depends="compile,copyWeb" description="--> build web application war package">
<war destfile="${dist.dir}/${app.name}.war" webxml="${build.dir}/WEB-INF/web.xml">
<fileset dir="${build.dir}" />
</war>
<copy tofile="${dist.dir}/config.properties" file="${conf.dir}/config.properties" />
<copy tofile="${dist.dir}/log4j.properties" file="${conf.dir}/log4j.properties" />
</target>

<target name="web.deploy" depends="web.war">
<copy file="${dist.dir}\${app.name}.war" todir="${jboss.dir}\server\${jboss.server}\deploy" />
</target>

<target name="ejb.jar" depends="compile" description="build the ejb jar">
<jar jarfile="${dist.dir}\${app.name}.jar">
<fileset dir="${build.dir}/WEB-INF/classes">
<include name="com/sillycat/ejb/**/*.class" />
</fileset>
</jar>
</target>

<target name="ejb.deploy" depends="ejb.jar">
<copy file="${dist.dir}\${app.name}.jar" todir="${jboss.dir}\server\${jboss.server}\deploy" />
</target>

<target name="all" depends="clean,web.deploy,ejb.deploy" description="clean, build jar package, generate api-doc">
</target>

</project>


build.properties文件如下:
app.name=easyejb
catalina.home=E:\\tool/apache-tomcat-6.0.20/
ant.encoding=UTF-8
java.level=1.5

jboss.home=E:\\jboss-5.1.0.GA/
jboss.server.config=default
启动JBOSS后,可以直接进行单元测试:
package com.sillycat.ejb;

import static org.junit.Assert.assertEquals;

import javax.naming.InitialContext;

import org.junit.BeforeClass;
import org.junit.Test;

public class HelloWorldTest {
protected static HelloWorld helloworld;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
InitialContext ctx = new InitialContext();
helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");
}

@Test
public void testSayHello() {
String result = helloworld.SayHello("EJB&SPRING");
assertEquals("EJB&SPRING回忆过去,痛苦的相思忘不了!", result);
}
}

按照要求撰写了Operation,OperationLocal,OperationBean,将jar和war都发布到JBOSS执行,出错如下:
Caused by: org.jboss.xb.binding.JBossXBException: Failed to create a new SAX parser
at org.jboss.xb.binding.parser.sax.SaxJBossXBParser.<init>(SaxJBossXBParser.java:97)
at org.jboss.xb.binding.UnmarshallerImpl.<init>(UnmarshallerImpl.java:56)
at org.jboss.xb.binding.UnmarshallerFactory$UnmarshallerFactoryImpl.newUnmarshaller(UnmarshallerFactory.java:96)
... 73 more
Caused by: java.lang.ClassCastException: org.apache.xerces.parsers.XML11Configuration cannot be cast to org.apache.xerces.xni.parser.XMLParserConfiguration
at org.apache.xerces.parsers.SAXParser.<init>(Unknown Source)
at org.apache.xerces.parsers.SAXParser.<init>(Unknown Source)

网上搜索了一下,说道的解决办法都是
删掉项目中的xerces-2.6.2.jar和xml-apis.jar两个文件!
我先测试EJB3,所以也删除掉了这些东东,当然这只是暂时这么做,这不是最后解决方案。

OperationBean.java如下:
package com.sillycat.ejb.impl;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import com.sillycat.ejb.Operation;
import com.sillycat.ejb.OperationLocal;
@Stateless
@Remote(Operation.class)
@Local(OperationLocal.class)
public class OperationBean implements Operation, OperationLocal {
private int total = 0;
public int Addup() {
total++;
return total;
}
}

测试的JSP,ejbTest1.jsp如下:
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="com.sillycat.ejb.*, javax.naming.*, java.util.Properties"%>
<%
InitialContext ctx = new InitialContext();
try {
//通过远程接口调用EJB
Operation remote = (Operation) ctx.lookup("OperationBean/remote");
out.println("<br>(通过远程接口调用EJB)累加的结果是:"+ remote.Addup());
} catch (Exception e) {
out.println("<br>远程接口调用失败");
}
out.println("<br>==============================================");
try {
//通过本地接口调用EJB
OperationLocal local = (OperationLocal) ctx.lookup("OperationBean/local");
out.println("<br>(通过本地接口调用EJB)累加的结果是:"+ local.Addup());
} catch (Exception e) {
out.println("<br>本地接口调用失败");
}
%>
页面显示的结果是:
(通过远程接口调用EJB)累加的结果是:7
==============================================
(通过本地接口调用EJB)累加的结果是:8

Stateless Session Bean一旦实例化就被加入实例池中,各个用户都可以用,即使用户已经消亡,Stateless Session Bean的生命也不一定结束。如果它有自己的属性(变量),那么这些变量就会受到所有使用它的用户的影响。

2.2 实例池化(Instance Pooling)
避免每次用户方法调用进行实例的创建和销毁。

2.2 stateless session bean的生命周期
它只有两个状态:does not exist 和 method-ready pool
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值