第一篇:@EJB注释的总结
SB InjectionBean
G:/dev/ws/SB/src/com/foshanshop/ejb3/Hello.java
G:/dev/ws/SB/src/com/foshanshop/ejb3/Injection.java
G:/dev/ws/SB/src/com/foshanshop/ejb3/impl/HelloBean.java G:/dev/ws/SB/src/com/foshanshop/ejb3/impl/InjectionBean.java
InjectionBean.java
package com.foshanshop.ejb3.impl;
import com.foshanshop.ejb3.Injection;
import com.foshanshop.ejb3.Hello;
import javax.ejb.Stateless;
import javax.ejb.Remote;
import javax.ejb.EJB;
@Stateless
@Remote(Injection.class)
public class InjectionBean implements Injection{
@EJB(beanName=“HelloBean”)Hello hello;
public String SayHello()
{
return hello.SayHello(“注入者”);
}
}
@EJB注释的name(), beanName(), mappedName()属性
1.不带任何属性使用
如:@EJB Hello hello;
当Hello接口在EJB-JAR文件内只被一个Bean class使用时,可以这样引用,那么 容器是如何解析这一引用的呢?以下JBOSS的解析引用
・对于@EJB Hello hello而言,唯一的标识符是Hello接口,JBOSS应用服务器首 先在注入的EJB-JAR中查找使用Hello作为其本地或远程接口的EJB.如果有多个 EJB使用Hello业务接口,则容器会抛出一个部署异常。
・如果EJB-JAR作为EAR的一个模块被部署,那么容器就会在其EAR中包含的 EJB-JAR中查找使用Hello作为本地或远程接口的EJB。同样,如果有多个EJB使用 Hello业务接口,则容器会抛出一个部署异常。
・如果容器没有在EAR中找到该EJB引用,则它会在其他的全局EJB-JAR中继续查找。
・如果指定了beanName()属性,JBOSS同样的查找过程,但是它所使用的唯一标 符识将是beanName()的值,如果指定了mappedName()属性,则JBOSS将不会 进行任何搜索,他根据mappedName()的值在全局JNDI中获取EJB引用。
第二篇:EJB中三种Bean的总结
EJB中三种Bean的总结
会话bean(session bean):负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都是通过实体bean来完成对数据库的操作。
会话bean分为两种:
无状态会话bean(Stateful Session Bean):平常我们使用最多的是无状态bean,因为它的bean实例可供多个用户使用,所以它的性能比有状态bean高。正因为一个bean实例被多个用户使用,那么前一个用户设置的值有可能被后一个用户所修改,所以它无法正确保存某个用户设置的值,因此是无状态的。
当客户机和服务器建立连接之后,无状态会话bean处理单一的用户请求或商务过程。无状态会话bean不需要从以前的请求中提取任何状态。例如,用户的用户密码确认。用户输入密码后,发送请求。组件返回真或假来确认用户,一旦过程完成,无状态会话bean也宣告结束。
如:
Java代码
import javax.ejb.Remote;
import javax.ejb.Stateless;
import com.mixele.ejb3.HelloWorld;
@Stateless //该注解指明这个程序是个无状态的会话Bean
@Remote(HelloWorld.class)
public class HelloWorldBean implements HelloWorld {
@Override
public String sayHello(String name){
return name + “Say: Hello,World!”;
}
}
有状态会话bean(Stateless Session Bean):有状态bean平常使用的并不多,因为它的一个bean实例只供一个用户使用,所以性能开销比较大,正因为它的实例只被一个用户使用,用户为它设置的值是不会被其他用户修改,所以可以正确保存用户设置的值,因此是有状态的。
当客户机和服务器建立连接之后,状态会话bean将一直在客户机和服务器之间保持着用户的某个状态。例如:用户使用银行的ATM时,经过验证之后,用户可以连续执行多次操作,在这个过程当中,用户的合法状态将一直被保留,直到她将信用卡取出,结束这次操作。这时,状态会话bean也就被销毁。
Java代码
@Stateful //该注解指明这个程序是个有状态的会话Bean
@Remote(HelloWorld.class)
@Local(HelloWorldLocal.class)
public class HelloWorldBeanStateful implements HelloWorld, HelloWorldLocal {
public String sayHello(String name){
return name + “ Say: Hello,World!--in HelloWorldBeanStateful”;
}
}
有状态Bean只是在类的注解上使用了:@Stateful
在代码上有状态Bean和无状态Bean区别不大,但是却是用了Bean实例的两种管理技术,即:
1.无状态bean使用实例池技术管理bean。
2.有状态bean使用激活(activation)管理bean。
每个用户都有自己的Bean实例,相当于有多少个用户就有多少个Bean实例为之服务。如果不采取任何机制,这样必然会导致服务器资源严重消耗,最后落个down机。为了解决这个问题,EJB引入了激活机制。激活机制实现的原理是这样的,在EJB服务器需要节省资源时,就从内存中收回bean实例,将其所保持的会话状态序列化到硬盘中,并且释放其所占有的内存,这个过程为钝化。若此时客户端对EJB再次发起请求,EJB容器会重新实例化一个Bean实例,并从硬盘中将之前的状态恢复。
实体bean(entity bean):它实际上属于java持久化规范(简称JPA)里的技术,JPA的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink等ORM框架各自为营的局面。
实体bean用来表示持久存储库里的一个东西。这通常就是指数据库里的一个东西,实体bean的一个实例就表示数据库表中的一行(不过,如果数据库得到了规范化,bean也有可能从多个表的数据行提取信息,也就是说,可能对应到多个表中的多个数据行)。实体bean的一个典型例子就是Customer(顾客),一个Customer实体bean可能表示Bo Olean,另一个Customer实体bean可能表示的是Trixia Lin。
实体bean只是数据模型,它不包括商务逻辑。实体bean可以将关系/对象数据库的数据映射到内存中供其它组件使用。实体bean是一直存在的,而且具有很高的容错性能。实体bean能供允许多用户同时访问。
如:
Java代码
@Entity //标注该Bean为实体Bean
@Table(name=“person”)//标注该Bean与数据库的person表进行映射
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
@Id //标注id属性是数据库表的主键,这个注解时实体Bean必须的@Column(name=“id”)//标注id属性与数据库表的id字段进行映射
@GeneratedValue(strategy=GenerationType.AUTO)//指定主键生成策略
public Integer getId(){ return id;}
public void setId(Integer id){ this.id = id;}
@Column(name=“name”,length=20,nullable=false)
public String getName(){ return name;}
public void setName(String name){ this.name = name;}
public int hashCode(){ ………… }
public boolean equals(Object obj){ ………… }
}
消息驱动bean(message-driven bean):它是专门用于异步处理java消息的组件,具有处理大量并发消息的能力。只有在需要一个JMS客户的时候才会实用消息驱动bean。换句话说,消息驱动bean可以监听来自JMS消息服务的消息。客户绝对不会直接调用消息驱动bean;要想让消息驱动做点什么事情,客户必须向一个消息服务发出一条消息。这说明,消息驱动bean没有相应的EJBObject,因为服务器会从消息服务直接得到客户请求,而不是当客户向bean发出调用时截获客户请求。NewCustomerNotification订购者就是一个典型的消息驱动bean。
消息驱动Bean(Message Driven Bean)定义:消息驱动是专门用来处理基于消息请求的组件。
消息模型:点对点消息传递和发布/订阅消息传递
点对点消息传递模型:一条信息只能传递给一个队列接收方
发布/订阅消息传递:一条消息可以由多个接收者接收
详细解析:首先它是无状态的Session Bean,客户端调用MDB时,无需等待,可以立即返回,MDB会异步处理客户的请求;MDB必须实现MessageListener接口,当容器守候检测到一条队列信息时,将调用onMessage()方法。
适用范围:当一个业务执行很长,然后又无需将结果实时反馈客户时,适合使用MDB;如订单成功后向客户发送一条成功短信或者一封邮件。
Queue消息:(PTP消息传递模型)通过注解可以描述消息驱动的属性相关信息:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName=“destinationType”,propertyValue=“javax.jms.Queue”),@ActivationConfigProperty(propertyName=“destination”,propertyValue=“queue/fashanshop”), })详解:@MessageDriven指明这是一个消息驱动,@ActivationConfigProperty注释配置信息的各种属性,destinationType指定消息类型为Queue队列,destination指定消息的路径;一旦队列到达指定的路径,则会触发onMessage方法,消息将作为参数传入。
-----Topic消息:(Pub/sub消息传递模型)通过注解可以描述消息驱动的属性相关信息:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName=“destinationType”,propertyValue=“javax.jms.Topic”),@ActivationConfigProperty(propertyName=“destination”,propertyValue=“top/student”), })详解:@MessageDriven指明这是一个消息驱动,@ActivationConfigProperty注释配置信息的各种属性,destinationType指定消息类型为Topic队列,destination指定消息的路径;一旦队列到达指定的路径,则会触发onMessage方法,消息将作为参数传入。
总结创建JMS的步骤: 查找JMS提供者(找到工厂)创建JMS连接(创建连接)
创建JMS Session(创建session对象)查找JMS目的地(借助JNDI查找JMS目的地)
创建JMS生产者或消费者(借助session和destination对象,客户能获得消息的生产者和消费者)
发送或接收消息(构建消息,借助生产者发送,消费者接收)
第三篇:java注释规范总结
在软件开发的过程中总是强调注释的规范,但是没有一个具体的标准进行说明,通常都是在代码编写规范中简单的描述几句,不能作为一个代码注释检查的标准和依据,做什么都要有一个依据吗:),现在我特整理了一个《Java的注释规范》,内容来自网络、书籍和自己的实际积累。
JAVA注释规范
版本/状态 作者 版本日期
1.0 ghc 2008-07-02
一、背景
1、当我们第一次接触某段代码,但又被要求在极短的时间内有效地分析这段代码,我们需要什么样的注释信息?
2、怎么样避免我们的注释冗长而且凌乱不堪呢?
3、在多人协同开发、维护的今天,我们需要怎么样的注释来保证高质、高交的进行开发和维护工作呢?
二、意义
程序中的注释是程序设计者与程序阅读者之间通信的重要手段。应用注释规范对于软件本身和软件开发人员而言尤为重要。并且在流行的敏捷开发思想中已经提出了将注释转为代码的概念。好的注释规范可以尽可能的减少一个软件的维护成本 , 并且几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护。好的注释规范可以改善软件的可读性,可以让开发人员尽快而彻底地理解新的代码。好的注释规范可以最大限度的提高团队开发的合作效率。长期的规范性编码还可以让开发人员养成良好的编码习惯,甚至锻炼出更加严谨的思维能力。
三、注释的原则
1、注释形式统一
在整个应用程序中,使用具有一致的标点和结构的样式来构造注释。如果在其他项目组发现他们的注释规范与这份文档不同,按照他们的规范写代码,不要试图在既成的规范系统中引入新的规范。
2、注释的简洁
内容要简单、明了、含义准确,防止注释的多义性,错误的注释不但无益反而有害。
3、注释的一致性
在写代码之前或者边写代码边写注释,因为以后很可能没有时间来这样做。另外,如果有机会复查已编写的代码,在今天看来很明显的东西六周以后或许就不明显了。通常描述性注释先于代码创建,解释性注释在开发过程中创建,提示性注释在代码完成之后创建。修改代码的同时修改相应的注释,以保证代码与注释的同步。
4、注释的位置
保证注释与其描述的代码相邻,即注释的就近原则。对代码的注释应放在其上方相邻或右方的位置,不可放在下方。避免在代码行的末尾添加注释;行尾注释使代码更难阅读。不过在批注变量声明时,行尾注释是合适的;在这种情况下,将所有行尾注释要对齐。
5、注释的数量
注释必不可少,但也不应过多,在实际的代码规范中,要求注释占程序代码的比例达到20%左右。注释是对代码的“提示”,而不是文档,程序中的注释不可喧宾夺主,注释太多了会让人眼花缭乱,注释的花样要少。不要被动的为写注释而写注释。
6、删除无用注释 在代码交付或部署发布之前,必须删掉临时的或无关的注释,以避免在日后的维护工作中产生混乱。
7、复杂的注释
如果需要用注释来解释复杂的代码,请检查此代码以确定是否应该重写它。尽一切可能不注释难以理解的代码,而应该重写它。尽管一般不应该为了使代码更简单便于使用而牺牲性能,但必须保持性能和可维护性之间的平衡。
8、多余的注释
描述程序功能和程序各组成部分相互关系的高级注释是最有用的,而逐行解释程序如何工作的低级注释则不利于读、写和修改,是不必要的,也是难以维护的。避免每行代码都使用注释。如果代码本来就是清楚、一目了然的则不加注释,避免多余的或不适当的注释出现。
9、必加的注释
典型算法必须有注释。在代码不明晰或不可移植处必须有注释。在代码修改处加上修改标识的注释。在循环和逻辑分支组成的代码中添加注释。为了防止问题反复出现,对错误修复和解决方法的代码使用注释,尤其是在团队环境中。
10、注释在编译代码时会被忽略,不编译到最后的可执行文件中,所以注释不
会增加可执行文件的大小。
四、JAVA注释技巧
1、空行和空白字符也是一种特殊注释。利用缩进和空行,使代码与注释容易区
别,并协调美观。
2、当代码比较长,特别是有多重嵌套时,为了使层次清晰,应当在一些段落的结束处加注释(在闭合的右花括号后注释该闭合所对应的起点),注释不能
写得很长,只要能表示是哪个控制语句控制范围的结束即可,这样便于阅读。
3、将注释与注释分隔符用一个空格分开,在没有颜色提示的情况下查看注释时,这样做会使注释很明显且容易被找到。
4、不允许给块注释的周围加上外框。这样看起来可能很漂亮,但是难于维护。
5、每行注释(连同代码)不要超过120个字(1024×768),最好不要超过80 字(800×600)。
6、Java编辑器(IDE)注释快捷方式。Ctrl+/ 注释当前行,再按则取消注释。
7、对于多行代码的注释,尽量不采用“/*......*/”,而采用多行“//”注释,这样虽然麻烦,但是在做屏蔽调试时不用查找配对的“/*......*/”。
8、注释作为代码切换开关,用于临时测试屏蔽某些代码。
例一:
//*/
codeSegement1;//*/
改动第一行就成了:
/*/
codeSegement1;//*/ 例二:
//----------------------第一段有效,第二段被注释
//*/
codeSegement1;/*/
codeSegement2;//*/
只需删除第一行的/就可以变成:
//----------------------第一段被注释,第二段有效
/*/
codeSegement1;/*/
codeSegement2;//*/
五、JAVA注释方法及格式
1、单行(single-line)--短注释://„„
单独行注释:在代码中单起一行注释,注释前最好有一行空行,并与其后的代码具有一样的缩进层级。如果单行无法完成,则应采用块注释。
注释格式:/* 注释内容 */
行头注释:在代码行的开头进行注释。主要为了使该行代码失去意义。
注释格式:// 注释内容
行尾注释:尾端(trailing)--极短的注释,在代码行的行尾进行注释。一般与代码行后空8(至少4)个格,所有注释必须对齐。
注释格式:代码 + 8(至少4)个空格 + // 注释内容
2、块(block)--块注释:/*„„*/ 注释若干行,通常用于提供文件、方法、数据结构等的意义与用途的说明,或者算法的描述。一般位于一个文件或者一个方法的前面,起到引导的作用,也可以根据需要放在合适的位置。这种域注释不会出现在HTML报告中。注释格式通常写成:
/*
* 注释内容
*/
3、文档注释:/**„„*/
注释若干行,并写入javadoc文档。每个文档注释都会被置于注释定界符
/**......*/之中,注释文档将用来生成HTML格式的代码报告,所以注释文
档必须书写在类、域、构造函数、方法,以及字段(field)定义之前。注释文档由两部分组成——描述、块标记。注释文档的格式如下:
/**
* The doGet method of the servlet.* This method is called when a form has its tag value method
* equals to get.* @param request
* the request send by the client to the server * @param response
* the response send by the server to the client * @throws ServletException * if an error occurred * @throws IOException * if an error occurred */
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doPost(request, response);}
前两行为描述,描述完毕后,由@符号起头为块标记注释。更多有关文档注
释和javadoc的详细资料,参见javadoc的主页: http://java.sun.com/javadoc/index.html
4、javadoc注释标签语法
@author
对类的说明 标明开发该类模块的作者
@version
对类的说明 标明该类模块的版本
@see
对类、属性、方法的说明 参考转向,也就是相关主题
@param
对方法的说明 对方法中某参数的说明
@return
对方法的说明 对方法返回值的说明
@exception 对方法的说明 对方法可能抛出的异常进行说明
六、JAVA注释具体实现
1、源文件注释
源文件注释采用 /** „„ */,在每个源文件的头部要有必要的注释信息,包括:文件名;文件编号;版本号;作者;创建时间;文件描述包括本文件历史修改记录等。中文注释模版:
/**
* 文 件 名 :
* CopyRright(c)2008-xxxx: * 文件编号:
* 创 建 人:
* 日
期:
* 修 改 人:
* 日
期:
* 描
述:
* 版 本 号:
*/
2、类(模块)注释:
类(模块)注释采用 /** „„ */,在每个类(模块)的头部要有必要的注释信息,包括:工程名;类(模块)编号;命名空间;类可以运行的JDK版本;版本号;作者;创建时间;类(模块)功能描述(如功能、主要算法、内部各部分之间的关系、该类与其类的关系等,必要时还要有一些如特别的软硬件要求等说明);主要函数或过程清单及本类(模块)历史修改记录等。
英文注释模版:
/**
* CopyRright(c)2008-xxxx:
<展望软件Forsoft >
* Project:
<项目工程名 >
* Module ID:
<(模块)类编号,可以引用系统设计中的类编号>
* Comments: <对此类的描述,可以引用系统设计中的描述>
* JDK version used:
* Namespace:
<命名空间>
* Author:
<作者中文名或拼音缩写>
* Create Date:
<创建日期,格式:YYYY-MM-DD>
* Modified By:
<修改人中文名或拼音缩写>
* Modified Date: <修改日期,格式:YYYY-MM-DD>
* Why & What is modified <修改原因描述>
* Version:
<版本号>
*/
如果模块只进行部分少量代码的修改时,则每次修改须添加以下注释:
//Rewriter
//Rewrite Date:<修改日期:格式YYYY-MM-DD> Start1:
/* 原代码内容*/ //End1:
将原代码内容注释掉,然后添加新代码使用以下注释:
//Added by
//Add date:<添加日期,格式:YYYY-MM-DD> Start2:
//End2:
如果模块输入输出参数或功能结构有较大修改,则每次修改必须添加以下
注释:
//Log ID:
//Rewrite Date:<模块修改日期,格式:YYYY-MM-DD>
2、接口注释:
接口注释采用 /** „„ */,在满足类注释的基础之上,接口注释应该包含描述接口的目的、它应如何被使用以及如何不被使用,块标记部分必须注明作者和版本。在接口注释清楚的前提下对应的实现类可以不加注释。
3、构造函数注释:
构造函数注释采用 /** „„ */,描述部分注明构造函数的作用,不一定有块标记部分。
注释模版一:
/**
* 默认构造函数
*/
注释模版二:
/**
* Description :
带参数构造函数,*
初始化模式名,名称和数据源类型
* @param schema:
模式名
* @param name:
名称
* @param type: 数据源类型
*/
4、函数注释:
函数注释采用 /** „„*/,在每个函数或者过程的前面要有必要的注释信息,包括:函数或过程名称;功能描述;输入、输出及返回值说明;调用关系及被调用关系说明等。函数注释里面可以不出现版本号(@version)。
注释模版一:
/**
* 函 数 名 :
* 功能描述:
* 输入参数:
<按照参数定义顺序>
*
<@param后面空格后跟着参数的变量名字
*
(不是类型),空格后跟着对该参数的描述。> *
* 返 回 值:-类型 <说明>
*
<返回为空(void)的构造函数或者函数,*
@return可以省略;如果返回值就是输入参数,必须 *
用与输入参数的@param相同的描述信息;必要的时*
候注明特殊条件写的返回值。> * 异
常:<按照异常名字的字母顺序> * 创 建 人: * 日
期: * 修 改 人: * 日
期: */
注释模版二:
/**
* FunName:
getFirstSpell
* Description :
获取汉字拼音首字母的字符串,*
被生成百家姓函数调用
* @param:
str the String是包含汉字的字符串
* @return String:汉字返回拼音首字母字符串;
*
英文字母返回对应的大写字母;
*
其他非简体汉字返回 '0';
* @Author:
ghc * @Create Date: 2008-07-02 */
5、方法注释:
方法注释采用 /** „„ */,对于设置(Set 方法)与获取(Get 方法)成员的方法,在成员变量已有说明的情况下,可以不加注释;普通成员方法要求说明完成什么功能,参数含义是什么且返回值什么;另外方法的创建时间必须注释清楚,为将来的维护和阅读提供宝贵线索。
6、方法内部注释:
控制结构,代码做了些什么以及为什么这样做,处理顺序等,特别是复杂的逻辑处理部分,要尽可能的给出详细的注释。
7、全局变量注释:
要有较详细的注释,包括对其功能、取值范围、哪些函数或者过程存取以及存取时注意事项等的说明。
8、局部(中间)变量注释:
主要变量必须有注释,无特别意义的情况下可以不加注释。
9、实参/参数注释:
参数含义、及其它任何约束或前提条件。
10、字段/属性注释: 字段描述,属性说明。
11、常量:常量通常具有一定的实际意义,要定义相应说明。
第四篇:注释格式
一、中文专著、学位论文、学术报告
序号、作者.文献题名.版本.出版地:出版者,出版年:起止页码。例如:
1、刘少奇.论共产党员的修养.修订2版.北京:人民出版社,1962:50。
2、张三.物权立法的本土资源研究.<博士论文>.北京:中国人民大学,2008:27-28。
二、中文期刊文章
序号、作者.文献题名.刊名,年,卷(期):起止页码。
例如:
3、李国海.论反垄断法制裁手段及其范围.中南大学学报(社会科学版),2005(2):193-198。
三、中文专著及论文集中的析出文献
序号、析出文献主要责任者.析出文献题名.载:原文献主要责任者.原文献题名.版本.出版地:出版者,出版年:析出文献起止页码
例如:
4、张光斗.也谈21世纪高等工程教育的改革.见:林功实.立足国内培养跨世纪研究生.北京:北京理工大学出版社,1996:105~110。
四、电子文献
序号、主要责任者.电子文献题名.电子文献的出处或可获得地址,发表或更新日期/引用日期(任选)。
5、王明亮.关于中国学术期刊标准化数据库系统工程的进展.http://,1998-10-04
五、外文文献
所引用语种通常注释体例。例如:
6、Scholkopf B, Smola,A.Learning with Kernels.Cambridge: MIT Press, 2002
注释格式如下:
引自期刊: ① 作者 : 《题名》,《刊名》,××××年第 ×期,第 × 页
引自专著: ② 作者 : 《书名》,出版者及×××× 年版,第 × 页
引自报纸: ③ 作者 : 《题名》,《报纸名》年-月-日(版次)参考文献著录格式如下:
引自期刊:[ 1] 作者(所有作者全列—下同).题名[ J].刊名 , 出刊年 ,卷(期): 起止页码.引自专著:[2] 作者.书名[ M].版次(初版不写).译者(指译著, 所有译者全列).出版地 : 出版者 , 出版年.页码.引自报纸:[3] 作者.题名[ N].报纸名 , 年-月-日(版次).引自论文集:[4] 作者.题名[ A].见 : 论文集编者.文集名[ C].出版地 : 出版者 , 出版年
第五篇:网络集群论文-EJB应用服务器集群技术分析
EJB应用服务器集群技术分析
2006年1月13日
前言
J2EE平台提供了一个基于组件的方法,用来设计、开发、装配及部署企业应用程序。而且提供了一个多层的分布式的应用模型、组件的复用、一致化的安全模型以及灵活的事务控制模型。近年来在企业系统中得到了大量使用。随着J2EE应用服务器的大量部署和客户访问量的猛增。企业对于J2EE系统的可伸缩性和高可用性要求越来越高,特别是在电子商务和金融领域,这个问题越显的突出。如何设计和构建一个具有可伸缩的,高可用性的J2EE集群应用服务器,成为设计J2EE应用服务器设计必须考虑的问题。但J2EE应用服务器的集群是基于EJB组件的集群,和普通Web Server集群技术有很大的不同。实现的方法也根本不相同。集群系统特点
一个集群系统是一群松散结合的服务器组,形成一个虚拟的服务器,为客户端用户提供统一的服务。对于这个客户端来说,通常在访问集群系统时不会意识到它的服务是由具体的哪一台服务器提供。集群系统一般应具高可用性、可伸缩性、负载均衡、故障恢复和可维护性等特殊性能。
高可用性是集群系统最基本的要求,它是对整个系统运行稳定性的一个评价。可伸缩性是指整个系统在随着客户端用户数量的增加而继续保持有效响应时间的能力。在一个可伸缩性系统中,随着用户数量的增加,有效响应时间变长,成线性变化关系,这也体现一个系统的峰值负载处理能力,但随着越来越多的系统处于Internet上,用户访问的峰值负载有效预测已变的不可能。用户访问量的猛增,使系统的有效响应时间成非线性变化,响应时间急剧变长,知道系统不堪重负而停机。一般的解决方法就是通过提升系统硬件系统,或通过增加服务器。但是不合理的增加服务器只能使整个集群系统变的越来越庞大,系统的这种复杂化就意味系统故障率变高,随之整个系统可靠性、可维护性都会降低。所以,一个系统的可用性和可伸缩性是一对矛盾的关系,而且和整个集群系统的实现方法有很大的关系。
2.EJB技术
EJB是J2EE应用平台的核心。Sun在EJB2.0规范中对EJB定义如下:EJB是用于开发和部署具多层结构的、分布式的、面向对象的Java应用系统跨平台的构件体系结构。EJB组件有三中类型:会话bean、实体bean、消息驱动bean。其中会话bean分为有状态和无状态两种。
EJB服务器的核心是提供EJB使用的一个或者多个EJB容器(Container)。EJB容器管理它所包含的EJB,为EJB组件的生存和执行提供了运行环境,同时也负责EJB的事务管理,安全管理,资源访问控制和一些异常处理。EJB容器不允许J2EE的客户端程序直接访问容器中EJB对象,当一个客户端用户想访问一个EJB,EJB规范中要求客户使用Java名字和目录接口JNDI(Java Naming and
Directory Interface)API来定位Bean的home接口。EJB服务器集群
EJB服务器的集群是基于组件的一种集群方式,和普通Web Server集群技术有很大的不同。实现的方法也不相同。又由于EJB规范中没有提供任何有关支持集群的标准,即使有的厂商在EJB服务器中提供了集群特性,但如何具体实现集群也是由厂商自己确定。实现的方法也各不相同。目前,大多数J2EE应用服务器都提供了集群功能,如Bea WebLogic应用服务器,开放源码的JBoss应用服务器,Sybase公司提供的J2EE应用服务器等都提供了集群功能。在EJB服务器集群设计中,负载均衡(Load Balance),EJB集群和HttpSession集群技术是设计中涉及到的主要技术。其中EJB集群的实现是整个系统实现的核心。
3.1负载均衡(Load Balance)
Load Balance 主要的目的在于将访问系统的负荷分散在不同的机器上,使整个系统吞吐量和并发性得到提高, 它能让多台服务器共同承担一些繁重的计算或I/O任务,从而消除网络瓶颈,提高网络的灵活性和可靠性。常见的方法如下: 循环DNS
DNS负载均衡是一种简单而有效的方法,该方法使用简单的域名查询IP地址来实现一种简单的负载均衡。任意给出一个地址,DNS服务器都有一个IP地址池与之对应。每次请求将域名转换成IP地址时,循环返回IP地址池中的下一个地址。故被称作DNS round-robin。当一个Client访问时,给请求JNDI的InitialContext客户端传递一个DNS名,作为命名服务器的URL,每个DNS名字被转换成一个不同的地址,使用这个技术,每个客户端InitailContext请求就被直接发送到不同的服务器上。负载均衡的一大缺点是:一旦某个服务器出现故障,即使及时修改了DNS设置,还是要等待足够的时间(因为DNS需要一定的刷新时间)才能发挥作用,在此期间,有些客户端用户访问仍旧将发送故障服务器上。
软件Proxy
软件Proxy维护连接到一系列服务器上的打开连接。当一个Client访问服务器时,先要经过这个软件代理,这个代理能通过一些负载均衡的算法(如采用类似DNS Round-robin、随机方法、访问权衡算法)把一个用户的访问重新定向到一个服务器。这个软件代理方法能够及时发现服务器死机或没有响应,有效地避免了DNS round-robin方法中出现地故障访问。
硬件均衡器
这种硬件均衡器一般采用地址转换技术,将一个外部IP地址映射为多个内部IP地址,对每次TCP连接请求动态使用其中一个内部地址,达到负载均衡的目的。一般可采用第四层(或4层以上)的交换机来实现,这种交换机是按照IP地址和TCP端口进行虚拟连接的交换,直接将数据包发送到目的计算机的相应端口。通过交换机就能将来自外部的初始连接请求,分别与内部的多个地址相联系,从而建立虚拟连接实现负载均衡。这种第四层交换基于硬件芯片,因此网络传输速度和交换速度远远超过普通软件代理方式。
3.2 EJB 集群技术
Client端要访问EJB容器中EJB都是先要先访问JNDI命名服务器[见2节EJB技术]。所以J2EE的EJB服务器的实现集群(Cluster)核心也就围绕着JNDI。根据集群对于JNDI命名树在系统中管理和组织的不同,一般EJB集群可以分为
下面三种:
1)JNDI树代理(Proxy)
Cluster中每个J2EE Application Server都维护一个自己的本地私有JNDI树,Cluster中的每个服务器不知道其它服务器的状态和存在情况,只有Proxy服务知道Cluster中每个服务器的状态,并且可以访问Cluster中任何一个服务器上的JNDI树,这就要求每个服务器在启动和启动后要不断地和Proxy服务保持联系,以便Proxy知道它们的工作情况和Cluster所有的EJB对象。Client访问EJB对象,首先要访问JNDI Proxy,通过Proxy,可以重新定向访问到Cluster中所有的EJB对象(见图2)。这种方法的优点是实现简单,只需要设计一个JNDI Proxy代理。对于每个应用服务器不做复杂要求;而且系统的伸缩性好,要升级系统,只是简单增加服务器就可以。但这种方法有一个致命的缺点,就是Proxy服务要是失败,整个Cluster系统将无法正常工作,可靠性差。
2)集中式JNDI树
采用集中式集群时,整个集群系统中仅有一个主命名服务器,它负责管理和维护集群中一个全局、集中的JNDI树,集群中所有的EJB服务器在启动后,都要把要发布的对象绑定在这台命名服务器上,每个EJB服务器不需要维护自己的私有JNDI树,由这台主命名服务器来维护。假如在集群中一个EJB要在多个服务器上部署,那么每个服务器可以把同一个home对象绑定到命名服务器上,当一个客户从命名服务器请求访问这个EJB的home对象,可以将所有的home对象引用都返回给客户端,或者可以按一种均衡算法返回一个服务器的home对象引用(见图3)。这种集中式方法要提高整个系统可靠性,必须考虑命名服务器的备份问题,往往在大系统同时采用多台命名服务器,命名服务器间可以采用JNDI树复制方式,或者采用EJB服务器在多台服务器上绑定方式。例如Sybase公司的EJB应用服务器就是采用这种方式,它采用采用CORBA Cos Naming Service集中的管理Cluster中所有应用服务器的JNDI树。采用这种集中式的设计模型,系统设计简单,但同时为系统带来了集中式所固有的缺陷。首先,当系统设计中要考虑到命名服务器备份问题,而且随着集群系统越来越大,命名服务器在整个系统种瓶颈问题越显突出。
3)分布式JNDI树
在这种模型中,Cluster中每台应用服务器都有自己的命名服务器,命名服务器不仅维护私有的本地JNDI树,同时维护一个全局共享JNDI树。本地JNDI树只绑定本地应用服务器中部署的对象,而全局JNDI树保存了Cluster中其他应用服务器上的本地JNDI树副本。这样Client访问任何一台命名服务器,通过它的本地私有和全局共享JNDI树就能定位整个系统中部署EJB对象。一般都是采用多播形式,当Cluster中一个应用服务器启动后,加入这个Cluster的多播组,然后再采用IP 多播技术复制它的本地JNDI树到Cluster中其他服务器上全局共享JNDI树,这样Cluster中其他服务器就拥有它的JNDI树副本。同时,这台应用服务器和Cluster中其它服务器之间一直要保持HeartBeats(心跳)检测,以随时检测其它服务器的活动状态,假如有一台服务器死机异常后,这台应用服务器就要从它的全局共享JNDI树中删除这台异常服务器JNDI副本,其它活动的服务器都要做类似的操作。这种分布式模型系统最大的优点是具有很强的伸缩性,系统中再添加一台服务器,其它的服务器可以不作任何的变动。而且整个系统采用分布式体系可用性增强,系统中任何一台服务器死机,都不会影响到整个系统的正常工作。这种方法也是目前采用最多的一种设计方法。BEA公司
WebLogic应用服务器和JBoss应用服务器就采用这种设计方法。
4.结语
在对于集群系统的方法分析侧重于JNDI树的实现问题,在实际的设计中还应该具体的考虑到两种会话Bean,实体Bean和消息驱动Bean对于集群方法实现的差异性以及它们的故障恢复技术。