EJB初步学习

 

今天简单学习了传说中的 EJB ,首先总的感觉,就是他的最重要的一个特点吧,就是能够使远程用户访问到本地或是服务器上的资源服务器。打个比方吧,传统的,还记得我们的第一个 JAVA 项目吧,那是个简单的对数据库增删改查的操作,用简单的界面来显示数据。那么当我们把这个项目打包发布之后,事必要把你自己的数据库也贡献出去,你做的软件在进行增删改查时也就只能对你机子上的一个数据库,别人如果想要对你这个数据库进行访问,那必须到你数据库所在的终端设备上才可以。而传说中 EJB 结合 JBOSS 正好可以克服这个问题,关于 JBOSS 是一个 EJB 容器,但似乎也有 WEB 服务器的作用,关于这点,我自己也不是很清楚,我使用过 tomcat 那个我知道是 WEB 服务器,这里我想可以是 JBOSS EJB 容器,但同时也集成了 WEB 服务器的功能吧。好,从官网上下载到 JBOSS ,该设置的都设置了, JBOSS 服务器成功运行,关于 JBOSS 的设置,网上很多资料,这里不在重复。但在这里讲我设置时遇到的一个上错误吧,当我在正确设置 JBOSS-HOME 后,但在以后的配置文件中调用系统这个属性时,经常是把 JBOSS-HOME 的变量在最后加上一个分号,从而使自己程序在访问这些配置时经常出错,当时我是用全路径名称。后来才发现不知道为什么,在我的 JBOSS-HOME 所在的路径中自动生成了一个带有分号的文件夹,我想可能是我的 JBOSS-HOME 指到那个地方去了吧。把这个文件夹删除后就可以正常使用了。
好慢慢来,首先是我的第一个 EJB 的例子, HelloWorld. 首先要说明的是 Bean ,关于这个 Bean 有很多,会话,实例等等。那么究竟什么是 Bean 呢在字典中查的意思也都不对。在这里暂且把 Bean 当作是一个包吧,把一些应用封装,毕竟是人为规定的,不用太计较了。
让我先来看看会话 Bean session bean session bean 是实现业务逻辑的地方,简单来说,像我们要实现两数相加或是从数据库中读取数据,都江堰市是通过 Session Bean 来实现的。这样说来很像三层开发模式中的逻辑层,也像 MAC 中的 C 层。根据是否可以维护会话状态, Session Bean 分为有状态 bean 和无状态 bean. 有状态 bean 可以维护会话状态,无状态 bean 不维护会话状态。要维护会话状态,意味 EJB 窗口要为每个用户创建一个 bean 实例,并通过该实例保存着与用户的会话状态。不维护会话状态,意味着一个 bean 实例不需要保存与某个用户的会话状态,这时一个 bean 实例可以为多个用户服务。可能说了这么多大家还是不太懂,怎么说呢,当我们把这个会话 bean 提交给 JBOSS 服务器后,客户端会请求调用这些 bean 来处理信息数据等,当客户端发送请求时,服务器端要生成 bean 对象给这个用户。无状态 bean 的意思就是这些创建之后都会放在一个 bean 池中,客户调用时池中有就从池中取,池中没有就创建,而有状态会对每个不同的用户创建一个 bean 实例。而要开发一个 Session Bean, 我们按面向对象的思维,要给这个 bean 定义接口和相应的实现类。从而这个接口分为了远程( remote )和本地( local )接口,在这里先说明一下,不强制要求你实现 remote local 接口,但实现两者是一个比较好的方法。
远程接口 (remote interface) ,定义了 session bean 的业务方法,而这些方法可以被来自 EJB 容器之外的其它应用使用。他通过的是 Socket 通信原理。
本地接口 (local interface) ,定义了 session bean 的业务方法,而这些方法可以被同处于 EJB 容器内的其它应用使用。因为 local 接口允许 bean 之间直接通过内在交互,没有分布式对象协议的开销,从而发送了性能。
Bean (bean class)   bean class 包含了业务逻辑,它是实现接口所有的方法。
下面用一个简单的图来表示 bean 的运行流程:
 
 
 

浏览器

http://localhost:8080/Helloworld/index.jsp
 
JSP Engineer
index.jsp
HelloWord helloword=(Helloword)ctx.lookUp();
Session bean EJB container
Jndi.properties
 
HelloWorldBean.class
浏览器请求index.jsp
编译JSP文件
查找存根对象
 

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

好下面开始编写 bean 了,在这之前首先要把 JBOSS 的一些 JAR 文件导入到项目中去,首先是 bean 接口,很简单根普通接口一样,方要是用来定义方法,和在调用时返回实现这个接口的存根。
然后是实现这个接口方法的实现类,当然这里叫 session bean ,建议类名后面加上 bean 表示这是一个实现类。在这个类上有几个标签要注意,第一组是 @Stateless,@Stateful. 第一个指定这个 bean 是无状态的 . 第二个当然是用状态的了。在这里面还可以指定这个 bean 的名字,为什么要指定呢,我打个比方,如果不指定名字那一个接口类有两 bean 实现,那我们调用的时候,究竟是调用哪个呢,这时编译器会报错的。当然我只是打个比方,其实在这里我们是可以不指定名字的,那肯定有默认的了,那这个默认的名字是什么呢,其实就是这个实现类的类名(不包含包结构),所以只要我们的类名不同,那我们完全可以不指定每个 bean 的名字。也可以很好的控制了。当然在这里还是要告诉大家指定 bean 名字的方法 :@Staeless(name=”xxx”), 还有一组是 @Remote( 接口的 class 文件名 ), @Local( 接口的 class 文件名 ) ,这组是用来指定接口是远程还是本地的。当然我们也可以指定多个接口。方法是: @Local({ 接口 1 class 文件名,接口 2 class 文件名。。。。。 }) 或分开有的是远程,有的本地。
好了这两步完成之后一个简单的 EJB 就完成了,接下来就是把它布暑到 JBOSS 中去了。关于布暑也有两种方法一种是利用开发工具自带的 jar 导出功能。这个很简单点 next 就行。还有一种方法也是在真正开发过程中常用的 Ant 打包方法。这种打包方法十分的方便。首先在当前项目的根目录下新建一个 XML 文件 , build.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<!--. 表示同一目录 .. 表示在上一目录 -->
 
<project name= "HelloWorld" basedir= "." >  //basedir 是指定该项目的目录,点表示为当前目录,也就是 build.xml 所在的目录
   <!-- 指定项目的源文件夹 -->
   <property name= "src.dir" value= "${basedir}/src" />
   <!-- 指定系统中的变量因为我们要从系统变量中得到值参考以下,简单的说就是引用系统的环境变量 -->
   <property environment= "env" />
   <property name= "jboss.home" value= "${env.JBOSS_HOME}" />
   <!-- 指定目前 Jboss 的配置项 -->
   <property name= "jboss.server.config" value= "default" />
   <!-- 指定后面编译类时存储的路径 -->
   <property name= "build.dir" value= "${basedir}/build" />
    <!-- 指定我们要用到 jboss jar 文件 -->
    <path id= "build.classpath" >
   
        <fileset dir= "${jboss.home}/client" >
            <include name= "*.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= " 编译 " >
    <javac srcdir= "${src.dir}" destdir= "${build.dir}" >
       <classpath refid= "build.classpath" />
    </javac>
    </target>
 
    <!-- 打包 -->
    <target name= "ejbjar" depends= "compile" description= " 创建 ejb 发布包 " >
       <jar jarfile= "${basedir}/${ant.project.name}.jar" >
           <fileset dir= "${build.dir}" >
            <include name= "**/*.class" />
            </fileset>
 
      
 
       
       </jar>
    </target>
 
    <target name= "deploy" depends= "ejbjar" description= "ejb 发布 " >
       <copy file= "${basedir}/${ant.project.name}.jar" todir= "F:/DirectRunSoft/jboss-5.1.0.GA-jdk6/jboss-5.1.0.GA/server/${jboss.server.config}/deploy" />
    </target>
                                                                                                                                                                               
    <target name= "undeploy" description= " 卸载 ejb" >
       <delete file= "F:/DirectRunSoft/jboss-5.1.0.GA-jdk6/jboss-5.1.0.GA/server/${jboss.server.config}/deploy/${ant.project.name}.jar" />
    </target>
                                                                                                                                                                              
  
 
</project>
 
当这个 Bean 发布成功后,我们可以到 http://localhost:8080/jmx-console 中去查看是否发布成功。(发布时要启动 JBOSS 服务器)
发布成功后就会生成一个 jndi.
什么叫 jndi 呢,其实不用管他,只要记着你发布之后,那 JBOSS 会给你一个号。而别人调用时,也是查这个号。差不多就是这意思了。
那么接下来我们就要创建一个客户端来访问这个 bean 服务了。说白了就是那个实现类中提供的方法。那如上文所说,首先是查找这个 jndi 号了。在查之前还有一个工作就是我们必须设置应用服务器( JBOSS )的上下文信息。主要是 jndi 的驱动类名 (java.naming.factory.initial) 和命名服务器提供者 URL(java.naming.provider.url).
那这两个是什么东东呢,呵呵,第一个,你可以作为 jndi 的驱动,上文不是讲你把 session bean 发布到了应用服务器之后,服务器会生成 jndi 吗,你查找的时候也是查找 这个所谓的 jndi ,那么我们肯定需要驱动吧,打个比方吧,你查找数据库时,也是要 Class.Form(driver) ,呵呵,对不。这个驱动在 JBOSS 中是有的,只要加载一下 (org.jnp.interface.NamingContextFactory)
第二个, url 根数据库操作提供的 url 有点像吧,那么我们加快一下数据库中的 url 是用来做什么的呢( url=jdbc:sqlserver://localhost 8080;Datebase=Student )一他指定这个数据库所在的主机和访问时的端口,然后数据库名字等等信息,那么类比而来,我先把这个 jndi url 写出来 (127.0.0.1:1099) 似乎比数据库的 url 更为简单,他其实是用来指定全程服务器的主机地址和端口号,你要查 jndi, 但你去哪查啊,从哪个端口去查。
除了以上两个属性还有两个属性也常用到,分别是 (java.naming.security.principal Context.SECURITY_PRINCIPAL) (java.naming.security.credentials Context.SECURITY_CREDENTIALS), 他们类似于数据库的用户名和密码。
 
Properties props= new Properties();
       props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
       props.setProperty("java.naming.provider.url", "127.0.0.1:1099");
// 上面是将配置信息注册进系统属性
        try {
            // 这是实现一个 jndi 的对象。
           InitialContext ctx= new InitialContext();
// 查找 jndi
           HelloWorld hellworld=(HelloWorld)ctx.lookup( "HelloWorldBean/remote" );
// 得到服务
           System. out .println(hellworld.sayHello( " 约定 291 天后 " ));
           System. out .println(hellworld.getClass().getName());
       } catch (NamingException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
       }
除了上面的在代码中显示加载相应配置之外,我们还可以使用配置文件,你可能已经发现一个问题,在实例化 jndi 对象的时候就是上面的 ctx, 我们并没有看到对上面配置的调用,其实 jndi 对象实例也可以这样写 InitialContext ctx= new InitialContext(props); ,如此似乎更直观一点但在实际中,还是上面的写法,因为加入参数反而会影响程序的可移植性,那么我们不传入参数,那 jndi 实例化时是会自动调用 System.getPropety() 方法来查找配置的。下面介绍使用配置文件的方法。因为如果没有指定 property jndi 还会在 classpath 中寻找 jndi.properties. 那么水到渠成。建一个这个配置文件就 O 了。
 
 
 
WEB 程序打包:
War 打包
1. 开发集成工具
2. 压缩软件,压缩格式 zip 然后再改成 war
3. Ant 打包:
jar ant 类似,但也有不同:
<? xml version="1.0" encoding="UTF-8"?>
 
< project name="EJBClient" default="war" basedir=".">
    < target name="war" description="create web bag">
       < war warfile="${basedir}/EJBTest.war" webxml="${basedir}/WEB-INF/web.xml">
           < fileset dir="${basedir}">
              < include name="*.jsp" />
           </ fileset >
           < classes dir="${basedir}/WEB-INF/classes">
              < include name="**/*.class" />
           </ classes >
           < lib dir="${basedir}/WEB-INF/lib"></lib>
       </ war >
    </ target >
</ project >
 
下面我们再来看看 bean 的生命周期,在 Session bean 的生命周期里,状态变化会触发生命周期事件的发生。如从 does not exit 状态进入 method-ready pool 状态会触发 @PostConstrut 事件。同样从 method-read pool 状态进入 does not exist 状态也会触发@PreDestory事件。有些时候我们需要定制session bean 的管理过程,打个比方,你想在实例化 bean 的时候进行一些变量的初始化,又或者是在 bean 实例被告销毁的时候关掉外部资源。这些都可以通过在 bean 类中定义生命周期的回调方法来实现。通过注释你可以将任何方法指定为回调方法,不同于 EJB2.1 的是,所有的回调方法都必须实现,即时是空。
  1. @PostConstruct: bean对象完成实例化时标注了这个注释的方法会立刻调用,每个bean class 只能定义一个这样的方法。此注释适用于有状态和无状态的bean.
  2. @PreDestory: 标注了这个注释的方法会在销毁一个无用的或者过期的bean实例之前调用。这个注释同时适用于有状态和无状态的bean.
  3. @PrePassivate: 当一个有状态的bean实例空闲时间过长,就会发生钝化(passivate).标注这个注释的方法会在钝化之前调用。Bean实例被钝化之后,在一段时间内如果仍然没有用户对bean实例进行操作,窗口将会从硬盘中删除它。以后任何针对该bean的方法的调用。窗器都会抛出例外。这个注释适用于有状态会话bean.
  4. @PostActivate当客户端再次使用已经被钝化的有状态bean时,EJB容器会重新实例化一个bean实例,并从中将之前的状态恢复,标注了这个注释的方法在洗涤完成时被调用。这个注释只适用于有状态会话bean.
  5. @Init 这个注释指定了有状态bean初始化的方法,它区别于@PostConstruct注释在于:多个@Init注释方法可以同时存在Session bean中,但每个bean实例只会有一个@Init注释的方法会被调用。@PostConstruct@Init之后被调用。
  6. Remove当客户端调用标注了@Remove注释的方法时,容器将在方法执行结束后把bean实例删除。
 
 
当我们在一个 EJB 中想调用另一个 EJB 对象时,传统的是实例化这个 object 就可以了,但在 ejb 中不行,因为 EJB 实例创建及销毁是由容器管理的。要在 bean 中要用其它 EJB 或资源,你必须通过 jNID 查找或注入注释。查找前文已经说过,这里介绍下注入方法:
使用 @EJB (beanName=”XXX”) HelloWorldBean2 hellowrld;
 
 
 
 
 
还有许多功能细节,暂时还用不到吧。好了下面我们进入实例 bean
持久化是位于 JDBC 之上的一个更高层的抽象。持久层将对象映射到数据库,以便在查询,装载,更新,或删除对象的时候,无须使用像 JDBC 那样繁琐的 API ,在 EJB 的早期版本中,持久化是 EJB 平台的一部分。从 EJB3 0 开始,持久化已经自成规范,被称为 Java Persistence API. 它定义了一种方法,可以将常规的普通 JAVA 对象( POJO )映射到数据库中去。这些普通的 JAVA 对象被称作 entity bean. 然后,创建一个 Entity Bean 对象相当于新建一个记录,删除一个 Entity Bean 会同时从数据库中删除对应记录。修改一个 Entity Bean, 容器也会自动将 Entity bean 的状态同步到数据库。同时 Java Persistence API 还定义了一种查询语句 (JPQL) 以便对 java 对象的处理。
 
 
 
下面我们就开发这个实体 bean ,首先进行的就是对 Jboss 数据源的配置,因为你创建实体 bean 是映射到数据库中去的,所以要加载相应的资源,在 JBOSS 安装目录 /docs/emamples/jca 目录中找到,名称为数据库名 +-ds.xml 的例子文件。在资源部署前,要把相应的数据库驱动拷贝到 server/default/lib 目录下,完成后,要重启 JBOSS 服务器,完成了,可以在 http://localhost:8080/jmx-console/ 查看相应的数据源信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值