??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲AV无码久久,亚洲欧洲精品视频在线观看,久久久久亚洲AV无码观看http://m.tkk7.com/TrampEagle/category/9798.html学习和生z? zh-cnTue, 27 Feb 2007 14:19:30 GMTTue, 27 Feb 2007 14:19:30 GMT60EJB技术及应用http://m.tkk7.com/TrampEagle/articles/28636.htmlTrampEagleTrampEagleThu, 19 Jan 2006 03:35:00 GMThttp://m.tkk7.com/TrampEagle/articles/28636.htmlhttp://m.tkk7.com/TrampEagle/comments/28636.htmlhttp://m.tkk7.com/TrampEagle/articles/28636.html#Feedback0http://m.tkk7.com/TrampEagle/comments/commentRss/28636.htmlhttp://m.tkk7.com/TrampEagle/services/trackbacks/28636.htmlhttp://www.cnjsp.org/view.jsp?column=2&id=739

一、EJB技术简?nbsp;
    EJB的全U是Enterprise java bean。是JAVA中的商业应用lg技术。EJBl构中的角色 EJB lgl构是基于组件的分布式计结构,是分布式应用pȝ中的lg?BR>一个完整的ZEJB的分布式计算l构由六个角色组成,q六个角色可以由不同的开发商提供Q每个角色所作的工作必须遵@Sun公司提供的EJB规范Q以保证彼此之间的兼Ҏ。这六个角色分别是EJBlg开发?Enterprise Bean Provider) 、应用组合?Application Assembler)、部|?Deployer)、EJB 服务器提供?EJB Server Provider)、EJB 容器提供?EJB Container Provider)、系l管理员(System Administrator)Q?BR>
二、EJB中各角色的分?/STRONG>

1、EJBlg开发?Enterprise Bean Provider)
EJBlg开发者负责开发执行商业逻辑规则的EJBlgQ开发出的EJBlg打包成ejb-jar文g。EJBlg开发者负责定义EJB的remote和home接口Q编写执行商业逻辑的EJB class,提供部vEJB的部|文?deployment descriptor)。部|文件包含EJB的名字,EJB用到的资源配|,如JDBC{。EJBlg开发者是典型的商业应用开发领域专家?BR>EJBlg开发者不需要精通系l的编E,因此Q不需要知道一些系l的处理细节,如事务、同步、安全、分布式计算{?BR>
2、应用组合?Application Assembler)
应用l合者负责利用各UEJBl合一个完整的应用pȝ。应用组合者有旉要提供一些相关的E序Q如在一个电子商务系l里Q应用组合者需要提供JSP(Java Server Page)E序?BR>应用l合者必L握所用的EJB的home和remote接口Q但不需要知道这些接口的实现?BR>
3、部|?Deployer)
部v者负责将ejb-jar文g部v到用Lpȝ环境中。系l环境包含某UEJB Server和EJB Container。部|者必M证所有由EJBlg开发者在部v文g中声明的资源可用Q例如,部v者必配|好EJB所需的数据库资源?BR>部vq程分两步:部v者首先利用EJB Container提供的工L成一些类和接口,使EJB Container能够利用q些cd接口在运行状态管理EJB?nbsp;部v者安装EJBlg和其他在上一步生成的cdEJB Container中?nbsp;部v者是某个EJBq行环境的专家?BR>某些情况下,部v者在部v时还需要了解EJB包含的业务方法,以便在部|完成后Q写一些简单的E序试?BR>
4、EJB 服务器提供?EJB Server Provider)
EJB 服务器提供者是pȝ领域的专Ӟ_N分布式交易理Q分布式对象理及其它系l的服务。EJB 服务器提供者一般由操作pȝ开发商、中间g开发商或数据库开发商提供?BR>在目前的EJB规范中,假定EJB 服务器提供者和EJB 容器提供者来自同一个开发商Q所以,没有定义EJB 服务器提供者和EJB容器提供者之间的接口标准?BR>
5、EJB 容器提供?EJB Container Provider)
EJB 容器提供者提供以下功能:
提供EJB部v工具为部|好的EJBlg提供q行环境 。EJB容器负责为EJB提供交易理Q安全管理等服务?BR>EJB 容器提供者必LpȝU的~程专家Q还要具备一些应用领域的l验。EJB 容器提供者的工作主要集中在开发一个可伸羃的,h交易理功能的集成在EJB 服务器中的容器。EJB 容器提供者ؓEJBlg开发者提供了一l标准的、易用的API讉KEJB 容器QEJBlg开发者不需要了解EJB服务器中的各U技术细节?BR>EJB容器提供者负责提供系l监工L来实时监EJB容器和运行在容器中的EJBlg状态?BR>
6、系l管理员(System Administrator)
pȝ理员负责ؓEJB服务器和容器提供一个企业的计和|络环境?BR>pȝ理员负责利用EJB 服务器和容器提供的监管理工LEJBlg的运行情c?BR>
三、EJB的体pȝ构:

    EJB分布式应用程序是Z对象lg模型的,低层的事务服务用了API技术。EJB技术简化了用JAVA语言~写的企业应用系l的开发,配置。EJB技术定义了一l可重用的组ӞEnterprise Beans。你可以利用q些lgQ象搭积木一L建立你的分布式应用程序。当你把代码写好之后Q这些组件就被组合到特定的文件中厅R每个文件有一个或多个Enterprise BeansQ在加上一些配|参数。最后,q些Enterprise Beans被配|到一个装了EJB容器的^C。客戯够通过q些Beans的home接口Q定位到某个beansQƈ产生q个beans的一个实例。这P客户p够调用Beans的应用方法和q程接口?BR>EJB服务器作为容器和低层q_的桥梁管理着EJB容器和函数。它向EJB容器提供了访问系l服务的能力。例如:数据库的理和事务的理Q或者对于其它的Enterprise的应用服务器。所有的EJB 实例都运行在EJB容器中?nbsp;   容器提供了系l的服务,控制了EJB的生命周期。EJB中的有一些易于用的理工具如:Security--配置描述器(The Deployment descriptorQ定义了客户能够讉K的不同的应用函数。容器通过只允许授权的客户讉Kq些函数来达到这个效果。Remote Connectivity--容器E链接管理着低层的通信issuesQ而且对Enterprise Beas的开发者和客户都隐藏了通信l节。EJB的开发者在~写应用Ҏ的时候,p是在条用本地的^CL。客户也不清楚他们调用的Ҏ可能是在q程被处理的。Life Cycle managment--客户单的创徏一个Enterprise beans的实例,q常取消一个实例。而容器管理着Enterprise Beans的实例,使Enterprise Beans实现最大的效能和内存利用率。容器能够这hȀzd使Enterprise Beans失效Q保持众多客户共享的实例池。等{?nbsp; Trasction management-配置描述器定义了Enterprise beans 的事务处理的需求。容器管理着那些理分布式事务处理的复杂的issues。这些事务可能要在不同的q_之间更新数据库。容器ɘq些事务之间互相独立Q互不干扰。保证所有的更新数据库都是成功发生的Q否者,回滚到事务处理之前的状态?BR>EJB lg是基于分布式事务处理的企业应用E序的组件。所有的EJB都有如下的特点:EJB包含了处理企业数据的应用逻辑。定义了EJB的客L面。这L界面不受容器和服务器的媄响。于是,当一个EJB被集合到一个应用程序中LQ不用更改代码和重新~译。EJB能够被定?nbsp;各种pȝU的服务Q例如安全和事务处理的特性,都不是属于EJBcȝ。而是由配|和l装应用E序的工h实现?nbsp;有两U类型的EJB: Session beans ?nbsp;entity beans.Session beans是一U作为单用户执行的对象。作为对q程的Q务请求的相应Q容器生一个Session beans 的实例。一个Session beans有一个用?从某U程度上来说Q一个Session bean 对于服务器来说就代表了它的那个用?Session beans 也能用于事务Q它能够更新׃n的数据,但它不直接描l这些共享的数据。Session beans 的生命周期是相对较短的。典型的是,只有当用户保持会话的时候,Session beans 才是zȝ的。一旦用户退ZQSession beans ׃再与用户相联pM。Session beans被看成是瞬时的,因ؓ如果容器崩溃了,那么用户必须重新建立一个新的Session对象来l会话?BR>Session bean典型的声明了与用L互操作或者会话。也是_Session bean了在客户会话期间Q通过Ҏ的调用,掌握用户的信息。一个具有状态的Session beanUCؓ有状态的Session bean.当用L止与Session beans互操作的时?会话l止了,而且Qbean 也不再拥有状态倹{Session bean也可能是一个无状态的 session bean.无状态的Session beansq不掌握它的客户的信息或者状态。用戯够调用beans的方法来完成一些操作。但是,beans只是在方法调用的时候才知道用户的参数变量。当Ҏ调用完成以后Qbeansq不l箋保持q些参数变量。这P所有的无状态的session beans的实例都是相同的Q除非它正在Ҏ调用期间。这P无状态的Session beansp够支持多个用?容器能够声明一个无状态的Session beans.能够Q何Session beans指定lQ何用?
Entity BeansҎ据库中的数据提供了一U对象的视图。例如:一个Entity bean能够模拟数据库表中一行相关的数据。多个client能够׃n讉K同一个Entity bean.多个client也能够同时的讉K同一个Entity bean.Entity beans通过事务的上下文来访问或更新下层的数据。这P数据的完整性就能够被保证。Entity Beans能存zȝҎ长的旉Qƈ且状态是持箋的。只要数据库中的数据存在QEntity beans׃直存zR而不是按照应用程序或者服务进E来说的。即使EJB容器崩溃了,Entity beans也是存活的。Entity Beans生命周期能够被容器或?nbsp;Beans自己理。如果由容器控制着保证 Entity beans持箋的issus。如果由Beans自己理Q就必须写Entity beans的代码,包括讉K数据库的调用?BR>Entity Beans是由主键Qprimary key 一U唯一的对象标识符Q标识的。通常Q主键与标识数据库中的一块数据,例如一个表中的一行,的主键是相同的。主键是client能够定位特定的数据块?BR>
四、开发EJB

1、类介绍Q?BR>开发EJB的主要步骤一般来_整个的开发步骤(开发,配置Q组装)包括如下几个斚w。开发:首先要定义三个类QBeancLw,Bean的本地和q程接口cR?nbsp;配置Q配|包括生配|描q器--q是一个XML文g、声明了Enterprise Bean的属性、绑定了bean的class文gQ包括stub文g和skeleton文gQ。最后将q些配置都放C个jar文g中。还需要在配置器中定义环境属性。组装应用程序:包括Enterprise beans安装到Server服务器中Q测试各层的q接情况。程序组装器若q个Enterprise Beans与其它的lgl合h。组合成一个完整的应用E序。或者将若干个Enterprise beansl合成一个复杂的Enterprise Bean。管理Enterprise Bean?BR>我们必须定义和编写一些EJB中的基本cR如Enterprise beanc:q是Enterprise bean内部应用逻辑的实现。编写Enterprise bean的远E接口类。编写Enterprise bean的本地接口类。说明主键类Q主键类只是对于Entity bean才需要的。在Enterprise bean的配|描q器中指定主键的名字。Enterprise beans提供者定义了q程接口和本地接口,实现了EJBcLw。Remote接口中提供了客户调用EJB实现的应用逻辑函数的接口。而home接口提供了生和定位remote接口实例的方法?BR>在Enterprise bean本ncȝ实现Q本地home接口Q远Eremote接口之间q没有正式的联系Q例如承关p)。但是,在三个类里声明的Ҏ却必遵守EJB里面定义的规范。例如: 你在Enterprise bean里面声明了一个应用程序的Ҏ或者说应用逻辑。也在beans的remote接口中声明了q个ҎQ那么,q两个地方必要同样的名字。Bean的实现里面必至有一个Create()ҎQejbCreate()。但是可以有多个带有不同参数的create()Ҏ?nbsp;   在home接口中,也必L相同的方法定义(参数的个数相同)。EjbCreate()Ҏq回的一个容器管理的持久对象。它们都q回一个容器管理持久性的主键倹{但是,在home的相应的Create()Ҏ中返回值的cd是remote接口?BR>注意Q实体bean的实现的ejbCreateҎ有点不同。实体bean可以不定义ejbCreateҎ。如果实体只是通过应用E序或通过数据库管理程序的途径被加到数据库中,实体beanq略了ejbCreateҎ。EjbCreateq回的值是主键cd。如果ejbCreateҎ是容器管理持久性的实体bean的方法,它的q回值就是NULLcd。如果实体bean实现了Bean理的持久性,ejbCreateҎp回值类型就是主键类型。容器的d是把各接口和Enterprise bean的实现类l合h。保证在~译时和q行Ӟ各接口和实现cL相对应的?BR>EJB的实现类Q各接口要从不同的基cMl承下来。一个会话bean必须实现基类javax.ejb.SessionBean。而实体bean必须实现基类javax.ejb.EntiyBean。这些EJB的基c都是从javax.ejb.EnterpriseBeanl承而来。而javax.ejb.EnterpriseBean又是从java.io.Serializablel承而来。每一个Enterprise Bean都必L一个remote接口。Remote接口定义了应用程序规定客户可以调用的逻辑操作。这些是一些可以由客户调用的公qҎQ通常由Enterprise beanscL实现。注意,Enterprise bean的客户ƈ不直接访问Bean。而是通过remote接口来访问。Enterprise beancȝremote接口扩展了javax.ejb.EJBObjectcȝ公共java接口。而Javax.ejb.EJBObject是所有remote接口的基cR其代码如下Q?BR>
CODE:

package javax.ejb;
public interface EJBObject extends java.rmi.Remote{
public EJBHome getEJBHome() throws java.rmi.RemoteException;
public Object getPrimaryKey() throws java.rmi.RemoteException;
public void Remove() throws java.rmi.RemtoeException, java.rmi.RemoveException
public Handle getHandle() throws java.rmi.RemoteException;
boolean isIdentical (EJBObject p0) throws java.rmi.RemoteException;
}


getEJBHome()Ҏ允许你取得一个相关的Home接口。对?nbsp;实体BeanQ用getPrimaryKeyQ)Ҏ获得实体Bean的主键倹{RemoveQ)可以删除一个Enterprise bean。具体的语义在各U不同类型的enterprise beans的生命周期中Q由上下文中解释的。方法getHandleQ)q回了一个Enterprise bean实例的持久的句柄。IsIndentical()Ҏ允许你去比较Enterprise beans是否相同?BR>
2、方法:
所有的remote接口中的Ҏ必须声明为公共(publicQ的Qƈ必须抛出java.rmi.RemotException异常。另外,所有的remote接口中的Ҏ定义的参数和都必L在RMI-IIOP中有效的。对每一个在remote接口中定义的ҎQ在Enterprise bean c里面都要有相应的方法。相应的Ҏ必须要有同样的名字,同样cd和数量的参数Q同Lq回|而且q要抛出同样的例外?nbsp;如下代码昄了一个ATM例子的会话bean的remote接口AtmQ。里面声明了一个应用方法transferQ)。黑体部分表CEJB规范中必要有的内容。Remote接口必须扩展javax.ejb.EJBObjectcR从客户端调用的Enterprise bean的每一个方法都必须在remote接口中声明。TransferQ)Ҏ抛出了两个意外。其中InSufficientFundsException例外是应用程序定义的意外?BR>
CODE:

Public interface Atm extends javax.ejb.EJBObject{
Public void transfer(String Source, String Target, float amount)
Throws java.rmi.RemoteException, InSufficientFundsException;
}


Home接口必须定义一个或多个的Create()Ҏ。每一个这LCreate()Ҏ都必d名ؓCreate。ƈ且,它的参数Q不是cdq是数量都必Mbeanc里面的ejbCreate()Ҏ对应。注意,home接口中的Create()Ҏ和beancMejbCreate()Ҏ的返回值类型是不同的。实体bean的home接口q包含findQ)Ҏ?nbsp;每一个Home接口都扩展了javax.ejb.EJBHome接口。如下代码显CZjavax.ejb.EJBHome接口的定义:
CODE:

package javax.ejb;
public interface EJBHome extends java.rmi.Remote() {
void remove(Handle handle) throws java.rmi.RemoteException,RemoveException;
void remove(Object primarykey) throws java.rmi.RemoteException,RemoveException;
EJBMetaData getEJBMetaData() throws RemoteException;
Homehandle getHomeHandle() throws RemoteException;
}


q里提供了两个removeQ)Ҏ来删除Enterprise bean的实例。第一个removeҎ是通过句柄来删除一个Enterprise bean的实例。第二个removeҎ通过主键来删除一个Enterprise bean的实例?nbsp;在众多的Enterprise bean实例中,句柄唯一的标识一个实例。一个句柄与它引用的Enterprise bean有相同的生命期。考虑一个实体对象,客户可以通过一个句柄来重新获得相应的Enterprise bean的实例。一个句柄能够对应一个Enterprise bean对象的多个实例。例如,即当Enterprise bean对象所在的L崩溃了,或者Enterprise bean对象在不同的机器之间UdQ句柄仍是有效的。这里的句柄是Serialized句柄Q与CORBA中的字符串化的CORBA对象的引用是怼的概c在EJBHome接口中的W二个remove操作通过其主键来军_要删除的Enterprise bean。主键可以是扩展了Java ObjectcȝMcdQ但是,必须要实现Java的Serializable接口。主键是标识实体bean的主要的Ҏ。通常Q主键是数据库中的一个关键字Q唯一的定义了由实体bean代表的数据?BR>ҎgetEJBMetaDataQ)q回了Enterprise bean对象的metadata接口。这个接口允许客戯得Enterprise bean的metadata信息。当开发工h~译链接应用E序的时候,或者配|工h配置的时候,可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口Qhomec,remote接口Q还有获得主键的Ҏ。也提供了一个isSesson()的方法来定在放q个home接口的对象是会话beanq是实体bean?nbsp;   IsStatelessSession()Ҏ指示q个会话bean是有状态还是无状态的。如下代码显CZjavax.ejb.EJBMetadata接口的定义部分的代码?BR>
CODE:

Public javax.ejb; Public interface EJBMetaData{
EJBHome getEJBHome();
Class getHomeInterfaceClass();
Class getRemoteInterfaceClasss();
Class getPrimaryKeyClass();
Boolean isSession();
Boolean isStatelesssSession();
}


Ҏ一个CreateQ)ҎQEJB规范定义了如下的命名U定。它的返回值是会话bean的remote接口的类型。方法的名字只能是Create()。对会话beancM的每一个ejbCreate()Ҏ都必L一个Create()与之对应?nbsp;对于每一个Create()Ҏ的参数的cd和数量都必须与会话beancM的ejbCreate()Ҏ相对应。方法必L出java.rmi.RemoteException例外?nbsp;Ҏ必须抛出javax.rmi.CreateExeption例外?nbsp;CreateQ)Ҏ的参数是用来初始化新的会话bean对象的?nbsp;如下代码昄了一个会话bean对象的不同的Create()ҎQ其中必ȝ部分用粗体显C:
CODE:

public interface AtmHome extends javax.ejb.EJBHome{
Atm create() throws java.rmi.RemoteException,javax.ejb.CreateException;
Atm create(Profile preferredProfile)
Throws java.rmi.RemoteExeption,javax.ehrows java.rmi.RemoteException,RemoveException;
EJBMetaData getEJBMetaData() throws RemoteException;
Homehandle getHomeHandle() throws RemoteException;
}


q里提供了两个removeQ)Ҏ来删除Enterprise bean的实例。第一个removeҎ是通过句柄来删除一个Enterprise bean的实例。第二个removeҎ通过主键来删除一个Enterprise bean的实例。在众多的Enterprise bean实例中,句柄唯一的标识一个实例。一个句柄与它引用的Enterprise bean有相同的生命期。考虑一个实体对象,客户可以通过一个句柄来重新获得相应的Enterprise bean的实例。一个句柄能够对应一个Enterprise bean对象的多个实例。例如,即当Enterprise bean对象所在的L崩溃了,或者Enterprise bean对象在不同的机器之间UdQ句柄仍是有效的。这里的句柄是Serialized句柄Q与CORBA中的字符串化的CORBA对象的引用是怼的概c?BR>在EJBHome接口中的W二个remove操作通过其主键来军_要删除的Enterprise bean。主键可以是扩展了Java ObjectcȝMcdQ但是,必须要实现Java的Serializable接口。主键是标识实体bean的主要的Ҏ。通常Q主键是数据库中的一个关键字Q唯一的定义了由实体bean代表的数据。方法getEJBMetaDataQ)q回了Enterprise bean对象的metadata接口。这个接口允许客戯得Enterprise bean的metadata信息。当开发工h~译链接应用E序的时候,或者配|工h配置的时候,可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口Qhomec,remote接口Q还有获得主键的Ҏ。也提供了一个isSesson()的方法来定在放q个home接口的对象是会话beanq是实体bean。IsStatelessSession()Ҏ指示q个会话bean是有状态还是无状态的。如下代码显CZjavax.ejb.EJBMetadata接口的定义部分的代码?BR>
CODE:

Public javax.ejb;
Public interface EJBMetaData{
EJBHome getEJBHome();
Class getHomeInterfaceClass();
Class getRemoteInterfaceClasss();
Class getPrimaryKeyClass();
Boolean isSession();
Boolean isStatelesssSession();
}


五、EJB的编E环境:

1?nbsp;使用Jbuilder
Jbuilder与EJB Container能够q行无缝q接。Jbuilder和Inprise的应用服务器包括了所有的开发和配置Enterprise Beans的工具以及所需要的库:q行和管理Enterprise Bean的容器、命名服务?nbsp;事务服务、Java数据库、开发Enterprise Beans所需要的API、一个增强的java-to-iiop~译器,支持值类型和RMI信号{等?BR>Jbuilderq提供了一个快速开发应用程序Enterprise Beans的工具和向导。通过单而且直观的步骤,向导帮助你徏立一个Enterprise Bean。自p定某些缺省|产生了bean的模板,在上面,我们可以增加我们自己的应用逻辑。Jbuilder也提供了一个EJB的接口生成向对{向导在Enterprise Bean的公共方法基上生成了Remote接口和Home接口。Jbuilderq提供一个配|器的向导帮助我们逐步的徏立XML描述器文件。ƈ生成的Stubs集中C个jar文g中?BR>
2、用Jbuilder之外的集成环境:
如果你用其它的除了别的集成环境QIDEQ。要定使用了集成环境IDE所带的容器工具。也要验证IDE是否支持EJB规范的相应的版本Q还要确定它是否正确的支持EJB的API?BR>要确定JD到所支持的EJB容器的版本。可以通过查Inprise的安装说明来定EJB容器所支持的支持JDK的版本?BR>在配|Enterprise Bean的时候,你必M用Inprise的应用服务器所提供的工兗这些工兯够编辑和修改W三方的代理商提供的Inprise配置描述器。还能够验证配置描述器,能够验证bean的源代码?BR>
六、一个简单的HELLO例子

1、安装Apusic Application Server
Note:以下以LinuxZQ来说明Apusic Application Server的安装过E。其他^台的安装Q可参考Apusic Application Server安装手册?BR>下蝲JDK1.3QApusic Application Server必须q行在jdk1.3以上环境中。可从以下站点下载最新JDK?BR>http://java.sun.com
下蝲Apusic Application Server
Apusic Application Server 试用版可从以下网址得到Q?BR>http://www.apusic.com/download/enter.jsp
在下载完成后Q你可以得到一个包Ҏ件apusic.zipQ选定安装目录Q假讑֮装到/usr下,则用以下命oQ?BR>cd /usr
jar xvf apusic.zip
/usr下会出现一个目录apusicQApusic Application Server的所有程序都被解压到/usr/apusic下?BR>以下\径加入到CLASSPATH?BR>/usr/apusic/lib/apusic.jar
$JAVA_HOME/lib/tools.jar
用以下命令运行Apusic Application Server
java -Xms64m com.apusic.server.Main -root /usr/apusic

2、定义EJBq程接口(Remote Interface)
M一个EJB都是通过Remote Interface被调用,EJB开发者首先要在Remote Interface中定义这个EJB可以被外界调用的所有方法。执行Remote Interface的类由EJB生成工具生成?BR>以下是HelloBean的Remote IntefaceE序Q?BR>
CODE:

package ejb.hello;

import java.rmi.RemoteException;
import java.rmi.Remote;
import javax.ejb.*;

public interface Hello extends EJBObject, Remote {

//this method just get "Hello World" from HelloBean.
public String getHello() throws RemoteException;
}


3、定义Home Interface
EJB容器通过EJB的Home Interface来创建EJB实例Q和Remote Interface一P执行Home Interface的类由EJB生成工具生成?BR>以下是HelloBean 的Home InterfaceE序Q?BR>
CODE:

package ejb.hello;

import javax.ejb.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;

/**
* This interface is extremely simple it declares only
* one create method.
*/
public interface HelloHome extends EJBHome {

public Hello create() throws CreateException,
RemoteException;

}


4、写EJBc?BR>在EJBcMQ编E者必ȝ出在Remote Interface中定义的q程Ҏ的具体实现。EJBcMq包括一?nbsp;EJB规范中定义的必须实现的方法,q些Ҏ都有比较l一的实现模版,~程者只需p_֊在具体业务方法的实现上?BR>以下是HelloBean的代码:
CODE:

package ejb.hello;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

public class HelloBean implements SessionBean {
static final boolean verbose = true;

private transient SessionContext ctx;

// Implement the methods in the SessionBean
// interface
public void ejbActivate() {
if (verbose)
System.out.println("ejbActivate called");
}

public void ejbRemove() {
if (verbose)
System.out.println("ejbRemove called");
}

public void ejbPassivate() {
if (verbose)
System.out.println("ejbPassivate called");
}

/**
* Sets the session context.
*
* @param SessionContext
*/
public void setSessionContext(SessionContext ctx) {
if (verbose)
System.out.println("setSessionContext called");
this.ctx = ctx;
}

/**
* This method corresponds to the create method in
* the home interface HelloHome.java.
* The parameter sets of the two methods are
* identical. When the client calls
* HelloHome.create(), the container allocates an
* instance of the EJBean and calls ejbCreate().
*/
public void ejbCreate () {
if (verbose)
System.out.println("ejbCreate called");
}
/**
* **** HERE IS THE BUSINESS LOGIC *****
* the getHello just return a "Hello World" string.
*/
public String getHello()
throws RemoteException
{
return("Hello World");
}
}


5、创建ejb-jar.xml文g
ejb-jar.xml文g是EJB的部|描q文Ӟ包含EJB的各U配|信息,如是有状态Bean(Stateful Bean) q是无状态Bean(Stateless Bean)Q交易类型等。ejb-jar.xml文g的详l信息请参阅EJB规范。以下是HelloBean的配|文Ӟ
CODE:

<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems Inc.//DTD Enterprise JavaBeans 1.2//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_2.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Hello</ejb-name>
<home>ejb.hello.HelloHome</home>
<remote>ejb.hello.Hello</remote>
<ejb-class>ejb.hello.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Hello</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>


6、编译和部v
~译Java源文件ƈ编译后class和ejb-jar.xml打包到Hello.jar
mkdir build
mkdir build/META-INF
cp ejb-jar.xml build/META-INF
javac -d build *.java
cd build
jar cvf Hello.jar META-INF ejb
cd ..
用EJB工具生成可部|到Apusic Application Server中运行的jar文g:
java com.apusic.ejb.utils.EJBGen -d /usr/apusic/classes/Hello.jar build/Hello.jar
增加/usr/apusic/classes/Hello.jar到CLASSPATH?BR>Hello.jar加入到Apusic Application Server配置文g中。在/usr/apusic/config/server.xml 加入以下几行Q?BR>
CODE:

<module>
<ejb>
<ejb-uri>classes/Hello.jar</ejb-uri>
<bean>
<ejb-name>Hello</ejb-name>
<jndi-name>HelloHome</jndi-name>
</bean>
</ejb>
</module>


启动服务?BR>java -Xms64m com.apusic.server.Main -root /usr/apusic

7、写客户端调用程?BR>您可以从Java ClientQJSPQServlet或别的EJB调用HelloBean?BR>调用EJB有以下几个步骤:
通过JNDI(Java Naming Directory Interface)得到EJB Home Interface
通过EJB Home Interface 创徏EJB对象Qƈ得到其Remote Interface
通过Remote Interface调用EJBҎ

以下是一个从Java Client中调用HelloBean的例子:
CODE:

package ejb.hello;

import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
import javax.ejb.*;
import java.rmi.RemoteException;

/**
* @author Copyright (c) 2000 by Apusic, Inc. All Rights Reserved.
*/
public class HelloClient{
public static void main(String args[]){
String url = "rmi://localhost:6888";
Context initCtx = null;
HelloHome hellohome = null;
try{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.apusic.jndi.InitialContextFactory");
env.put(Context.PROVIDER_URL, url);
initCtx = new InitialContext(env);
}catch(Exception e){
System.out.println("Cannot get initial context: " + e.getMessage());
System.exit(1);
}
try{
hellohome = (HelloHome)initCtx.lookup("HelloHome");
Hello hello = hellohome.create();
String s = hello.getHello();
System.out.println(s);
}catch(Exception e){
System.out.println(e.getMessage());
System.exit(1);
}
}

}


q行HelloClientQ可得到以下输出Q?BR>Hello World 


TrampEagle 2006-01-19 11:35 发表评论
]]>
漫谈EJB (2)http://m.tkk7.com/TrampEagle/articles/28634.htmlTrampEagleTrampEagleThu, 19 Jan 2006 03:33:00 GMThttp://m.tkk7.com/TrampEagle/articles/28634.htmlhttp://m.tkk7.com/TrampEagle/comments/28634.htmlhttp://m.tkk7.com/TrampEagle/articles/28634.html#Feedback0http://m.tkk7.com/TrampEagle/comments/commentRss/28634.htmlhttp://m.tkk7.com/TrampEagle/services/trackbacks/28634.html 引自Q?A >http://www.cnjsp.org/view.jsp?column=2&id=560
  
     EJB技术的基础是另外两U技术:RMI-IIOP和JNDI。要想了解EJBQ一定要先了解RMI-IIOP和JNDI。因此,我们在介lEJBl节之前Q先了解q两Ҏ术。我们的介绍比较基本Q因此大多数l织只要了解q些已l够了?BR>
Java RMI-IIOP

    Java RMI-IIOPQJava Remote Method Invocation over the Internet Inter-ORB ProtocolQ是J2EE的网l机制。Java RMI-IIOP允许你编写分布式对象Q得对象的通信范围能够在内存中Q跨Java虚拟机,跨物理设备?BR>
Remote Method Invocation

    RPCQremote procedure callQ是一台机器的q程调用另一台机器的q程的过E。而remote method invocation则比RPC的概忉|q一步,允许分布式对象间的通信。RMI-IIOP允许调用q程对象的方法,而不仅仅是过E。这有利于面向对象编E。Java RMI QRemote Method Invocation q程Ҏ调用Q是用Java在JDK1.1中实现的Q它大大增强了Java开发分布式应用的能力。Java作ؓ一U风靡一时的|络开发语aQ其巨大的威力就体现在它强大的开发分布式|络应用的能力上Q而RMI是开发百分之癄Java的网l分布式应用pȝ的核心解x案之一。其实它可以被看作是RPC的Java版本。但是传lRPCq不能很好地应用于分布式对象pȝ。而Java RMI 则支持存储于不同地址I间的程序对象之间彼此q行通信Q实现远E对象之间的无缝q程调用?BR>
    remote method invocation决不单,需要考虑几个问题Q?BR>
    marshalling和unmarshalling.在不同机器间通过|络传递变量(包括Java基本cd和对象)Q如果目标机器表C数据的方式和原机器不同该怎么办?例如二进制库不同。因此marshalling和unmarshalling是传递变量的q程?BR>
    变量传递方?变量有两U传递方法:pass-by-value和pass-by-reference。对于前者,你的目标Ҏ只需使用一份copyQ但对于后者,q程Ҏ对变量的M修改都会影响到源数据?BR>
    |络和机器的不稳?需要有一U机制保证一个JVM崩溃之后Q不会媄响系l的正常q作?BR>
    ?nbsp;Java 分布式对象模型中Qremote object 是这样一U对象:它的Ҏ可以从其?nbsp;Java 虚拟机(可能在不同的L上)中调用。该cd的对象由一U或多种 remote interfacesQ它是声明远E对象方法的 Java 接口Q描q。远E方法调?nbsp;(RMI) 是调用q程对象上远E接口的Ҏ的动作。更为重要的是,q程对象的方法调用与本地对象的方法调用语法相同?BR>
Remote Interface

    RMI-IIOP遵@了接口和实现的原则。你写的所有网l代码都是应用于接口Q而不是实现。实际上Q你必须使用RMI-IIOP中的范例Q没有其它的选择。直接在你的对象实现上执行远E调用是不可能的Q你只能在对象类的接口上单独q行q一操作?BR>
    所以我们在使用RMI-IIOPӞ你必d立一个客h口,叫做remote interface。这个远E接口应该扩展java.rmi.Remote接口?BR>
Remote Object Implementation

    q程对象和客h的物理位|ƈ不是很重要。可以运行在同一地址I间或是跨Internetq行?BR>
    Z使对象成Z个远E对象,你需要执行一下步骤:

    l承javax.rmi.PortableRemoteObject。PortableRemoteObject是进行远E调用的基类Q当你的q程对象调用构造器ӞPortableRemoteObject对象的构造器也会自动被调用?BR>
    不承javax.rmi.PortableRemoteObject。如果你的远E对象需要承其它的c,而Java不允许多重承,因此你不能承PortableRemoteObject。这Ӟ你需要手动调用javax.rmi.PortableRemoteObject.exportObject()?BR>
Stub和Skeletons

    我们来看看在RMI-IIOP背后隐藏的网l架构。RMI-IIOP的一个好处就是你可以不用你要调用的对象是本地的q是q程的。这叫做local/remote transparency?BR>
    RMI应用E序通常包括两个独立的程序:服务器程序和客户机程序。典型的服务器应用程序将创徏多个q程对象Qɘq些q程对象能够被引用,然后{待客户用这些远E对象的Ҏ。而典型的客户机程序则从服务器中得C个或多个q程对象的引用,然后调用q程对象的方法。RMI为服务器和客hq行通信和信息传递提供了一U机制?BR>





    在与q程对象的通信q程中,RMI使用标准机制Qstub和skeleton。远E对象的stub担当q程对象的客hC表或代理艌Ӏ调用程序将调用本地stub的方法,而本地stub负责执行对q程对象的方法调用。在RMI中,q程对象的stub与该q程对象所实现的远E接口集相同。调用stub的方法时执行下列操作:(1) 初始化与包含q程对象的远E虚拟机的连接;(2) 对远E虚拟机的参数进行编l(写入q传输)Q?3) {待Ҏ调用l果Q?4) 解编Q读取)q回值或q回的异常;(5) D回给调用E序。ؓ了向调用E序展示比较单的调用机制Qstub参数的序列化和|络U通信{细节隐藏了h。在q程虚拟ZQ每个远E对象都可以有相应的skeletonQ在JDK1.2环境中无需使用skeletonQ。Skeleton负责调用分配给实际的远E对象实现。它在接收方法调用时执行下列操作Q?1) 解编Q读取)q程Ҏ的参敎ͼ(2) 调用实际q程对象实现上的ҎQ?3) 结果(q回值或异常Q编l(写入q传输)l调用程序。stub和skeleton由rmic~译器生成?BR>
    要实现local/remote transparency可没有那么简单。ؓ了屏蔽你调用的是q端L上的对象QRMI-IIOP需要模拟一个本地对象供你调用。这个本地对象叫做stub。它负责接受本地的方法调用请求,把这些请求委托给真正实现它们的对象(可以通过|络定位Q。这样就使得q程调用看v来就和本地调用一栗?BR>
    利用RMI~写分布式对象应用程序需要完成以下工作:(1) 定位q程对象。应用程序可使用两种机制中的一U得到对q程对象的引用。它既可用RMI的简单命名工具rmiregistry来注册它的远E对象,也可以将q程对象引用作ؓ常规操作的一部分来进行传递和q回。(2Q与q程对象通信。远E对象间通信的细节由RMI处理Q对于程序员来说Q远E通信看v来就像标准的JavaҎ调用。(3Q给作ؓ参数或返回g递的对象加蝲cd节码。因为RMI允许调用E序纯Java对象传给q程对象Q所以,RMI提供必要的机制Q既可以加蝲对象的代码又可以传输对象的数据。在RMI分布式应用程序运行时Q服务器调用注册服务E序以名字与远E对象相兌。客h在服务器上的注册服务E序中用q程对象的名字查找该q程对象Q然后调用它的方法?BR>
    定位q程对象。应用程序可使用两种机制中的一U得到对q程对象的引用。它既可?nbsp;RMI 的简单命名工?nbsp;rmiregistry 来注册它的远E对象;也可远E对象引用作为常规操作的一部分来进行传递和q回?nbsp;

    与远E对象通讯。远E对象间通讯的细节由 RMI 处理Q对于程序员来说Q远E通讯看v来就象标准的 Java Ҏ调用。给作ؓ参数或返回g递的对象加蝲cd节码因ؓ RMI允许调用E序纯 Java 对象传给q程对象Q所?nbsp;RMI 提供必要的机制Q既可以加蝲对象的代码又可以传输对象的数据。服务器调用注册服务E序以名字与远E对象相兌。客h在服务器注册服务E序中用q程对象的名字查找该q程对象Q然后调用它的方法。RMI 能用 Javapȝ支持的Q?nbsp;URL 协议Q例?nbsp;HTTP、FTP、file {)加蝲cd节码?BR>
    stub只是解决了一半的问题。我们还希望q程对象也不用考虑|络问题。因此远E对象也需要一个本地的skeleton来接受调用。skeleton接受|络调用q把调用委托l远E对象实现?BR>
    你的J2EE服务器应当提供一U方法来产生必须的stub和skeletonQ以减轻你的对网l问题考虑的负担。典型的是通过命o行工h完成Q例如sun的J2EE参考实现包׃用了一个名为rmicQRMI compilerQ的工具来生stub和skeletoncR你应当把stub部v在客h上,q把skeleton部v在服务器上?BR>
对象序列化和变量传?BR>
    在RMI分布式应用系l中Q服务器与客h之间传递的Java对象必须是可序列化的对象。不可序列化的对象不能在对象中q行传递。对象序列化扩展了核心Java输入/输出c,同时也支持对象。对象序列化支持把对象编码以及将通过它们可访问到的对象编码变成字节流Q同Ӟ它也支持中对象囑Ş的互补重构造。序列化用于d持久性和借助于套接字或远E方法调?RMI)q行的通信。序列化中现在包括一?nbsp;APIQApplication Programming InterfaceQ应用程序接口)Q允许独立于cȝ域指定对象的序列化数据,q允怋用现有协议将序列化数据域写入中或从中dQ以保与缺省读写机制的兼容性?BR>
    为编写应用程序,除多数瞬态应用程序外Q都必须具备存储和检?nbsp;Java对象的能力。以序列化方式存储和索对象的关键在于提供重新构造该对象所需的够对象状态。存储到的对象可能会支?nbsp;SerializableQ可序列化)?nbsp;ExternalizableQ可外部化)接口。对于Java对象Q序列化形式必须能标识和校验存储其内容的对象所属的 Javac,q且该内容q原为新的实例。对于可序列化对象,将提供_的信息将的域还原ؓcȝ兼容版本。对于可外部化对象,cd全权负责其内容的外部格式。序列化 Java 对象的目的是Q提供一U简单但可扩充的机制Q以序列化方式维?nbsp;Java对象的类型及安全属性;h支持~组和解~的扩展能力以满E对象的需要;h可扩展性以支持 Java 对象的简单持久性;只有在自定义Ӟ才需Ҏ个类提供序列化自实现Q允许对象定义其外部格式?BR>
java.rmi.Remote 接口 

    ?nbsp;RMI 中,q程接口是声明了可从q程 Java 虚拟Z调用的方法集。远E接 
口必L下列要求: 

    q程接口臛_必须直接或间接扩?nbsp;java.rmi.Remote 接口?nbsp;
    q程接口中的Ҏ声明必须满下列q程Ҏ声明的要求: 
    q程Ҏ声明在其 throws 子句中除了要包含与应用程序有关的异常Q注意与应用E序有关的异常无需扩展 java.rmi.RemoteException Q之外,q必d?nbsp;java.rmi.RemoteException 异常Q或它的类Q例如java.io.IOException ?nbsp;java.lang.Exception Q?nbsp;
    q程Ҏ声明中,作ؓ参数或返回值声明的Q在参数表中直接声明或嵌入到参数的非q程对象中)q程对象必须声明E接口,而非该接口的实现cR?BR>
    java.rmi.Remote 接口是一个不定义Ҏ的标记接口: 

public interface Remote 

    q程接口必须臛_扩展 java.rmi.Remote 接口Q或其它扩展java.rmi.Remote 的远E接口)。然而,q程接口在下列情况中可以扩展非远E接口: 

    q程接口也可扩展其它非远E接口,只要被扩展接口的所有方法(如果有)满q程Ҏ声明的要求?nbsp;
    例如Q下面的接口 BankAccount 即ؓ讉K银行帐户定义了一个远E接口。它包含往帐户存款、帐户收支q和从帐户取款的远E方法: 

public interface BankAccount extends java.rmi.Remote 

public void deposit(float amount) 
throws java.rmi.RemoteException; 
public void withdraw(float amount) 
throws OverdrawnException, java.rmi.RemoteException; 
public float getBalance() 
throws java.rmi.RemoteException; 


    下例说明了有效的q程接口 Beta。它扩展非远E接?nbsp;AlphaQ有q程ҎQ和接口 java.rmi.RemoteQ?nbsp;
public interface Alpha 

public final String okay = "constants are okay too"; 
public Object foo(Object obj) 
throws java.rmi.RemoteException; 
public void bar() throws java.io.IOException; 
public int baz() throws java.lang.Exception; 


public interface Beta extends Alpha, java.rmi.Remote { 
public void ping() throws java.rmi.RemoteException; 


RemoteException c?nbsp;

    java.rmi.RemoteException cL在远E方法调用期间由 RMI q行时所抛出的异常的类。ؓ保使用 RMI pȝ的应用程序的健壮性,q程接口中声明的q程Ҏ在其 throws 子句中必L?nbsp;java.rmi.RemoteExceptionQ或它的类Q例?nbsp;java.io.IOException ?nbsp;java.lang.ExceptionQ?nbsp;

当远E方法调用由于某U原因失败时Q将抛出 java.rmi.RemoteException 异常。远E方法调用失败的原因包括Q?nbsp;

    通讯p|Q远E服务器不可达或拒绝q接Q连接被服务器关闭等。) 
    参数或返回g输或d时失?nbsp;
    协议错误 

    RemoteException cL一个已验的异常Q必ȝq程Ҏ的调用程序处理ƈl编译器验的异常Q,而不?nbsp;RuntimeException?nbsp;

RemoteObject cd其子c?nbsp;

    RMI 服务器函数由 java.rmi.server.RemoteObject 及其子类java.rmi.server.RemoteServer、java.rmi.server.UnicastRemoteObject?nbsp;java.rmi.activation.Activatable 提供?nbsp;

    java.rmi.server.RemoteObject 为对q程对象敏感?nbsp;java.lang.ObjectҎ、hashCode?nbsp;equals ?nbsp;toString 提供实现?nbsp;

    创徏q程对象q将其导出(使它们可E客h利用Q所需的方法由cUnicastRemoteObject ?nbsp;Activatable 提供。子cd以识别远E引用的语义Q例如服务器是简单的q程对象q是可激zȝq程对象Q调用时执行的q程对象Q。java.rmi.server.UnicastRemoteObject cd义了单体Q单路传送)q程?BR>象,其引用只有在服务器进E活着时才有效。类 java.rmi.activation.Activatable 是抽象类Q它定义?nbsp;activatableq程对象在其q程Ҏ被调用时开始执行ƈ在必要时自己关闭?nbsp;

实现q程接口 

    实现q程接口的类的一般规则如下: 

    该类通常扩展 java.rmi.server.UnicastRemoteObjectQ因而将l承cjava.rmi.server.RemoteObject 和java.rmi.server.RemoteServer 提供的远E行为?BR>    该类能实CQ意多的远E接口?nbsp;
    该类能扩展其它远E实现类?nbsp;
    该类能定义远E接口中不出现的ҎQ但q些Ҏ只能在本C用而不能在q程使用?nbsp;

    例如Q下面的c?nbsp;BankAcctImpl 实现 BankAccount q程接口q扩展java.rmi.server.UnicastRemoteObject c: 

package mypackage; 

import java.rmi.RemoteException; 
import java.rmi.server.UnicastRemoteObject; 

public class BankAccountImpl extends UnicastRemoteObject implements 
BankAccount 


private float balance = 0.0; 

public BankAccountImpl(float initialBalance) 
throws RemoteException 

balance = initialBalance; 


public void deposit(float amount) throws RemoteException 

... 


public void withdraw(float amount) throws OverdrawnException, 
RemoteException 

... 


public float getBalance() throws RemoteException 

... 




    注意Q必要时Q实现远E接口的c能扩展除java.rmi.server.UnicastRemoteObject cM外的其它一些类。但实现cL时必L担v一定的责QQ即导出对象Q由 UnicastRemoteObject 构造函数负责)和实C java.lang.Object cȝ承的 hashCode?nbsp;equals 和toString Ҏ的正远E语义(如果需要)?nbsp;


q程Ҏ调用中的参数传?nbsp;

    传给q程对象的参数或源于它的q回值可以是L可序列化?nbsp;Java 对象。这包括 Java 基本cd, q程?Java 对象和实?nbsp;java.io.Serializable 接口的非q程 Java 对象。有兛_何ɾcd列化的详l信息,参见 Java“对象序列化规范”。本地得不到的作为参数或q回值的c,可通过 RMI pȝq行动态下载?nbsp;

传递非q程对象 

    非远E对象将作ؓq程Ҏ调用的参C递或作ؓq程Ҏ调用的结果返回时Q是通过复制传递的Q也是使用 Java 对象序列化机制将该对象序列化。因此,在远E对象调用过E中Q当非远E对象作为参数或q回g递时Q非q程对象的内容在调用q程对象之前被复制。从q程Ҏ调用q回非远E对象时Q将在调用的虚拟Z创徏新对象?nbsp;

传递远E对?nbsp;

    当将q程对象作ؓq程Ҏ调用的参数或q回g递时Q远E对象的 stub E序卌传递出厅R作为参C递的q程对象仅能实现q程接口?nbsp;

引用的完整?nbsp;

    如果一个对象的两个引用在单个远E方法调用中以参数Ş式(或返回值Ş式)从一个虚拟机传到另一个虚拟机中,q且它们在发送虚拟机中指向同一对象Q则两个引用在接收虚拟机中将指向该对象的同一副本。进一步说是Q在单个q程Ҏ调用中,RMI pȝ在作ؓ调用参数或返回g递的对象中保持引用的完整性?nbsp;

cL?nbsp;

    当对象在q程调用中被从一个虚拟机发送到另一个虚拟机中时QRMI pȝ在调用流中用cȝ信息 (URL) l类描述W加注解Q以便该c能在接收器上加载。在q程Ҏ调用期间Q调用可随时下蝲cR?nbsp;

参数传输 

    为将 RMI 调用的参数序列化到远E调用的目的文g里,需要将该参数写入作为java.io.ObjectOutputStream cȝ子类的流中。ObjectOutputStream 子类覆?nbsp;replaceObject ҎQ目的是用其相应?nbsp;stub cd代每个远E对象。对象参数将通过 ObjectOutputStream ?nbsp;writeObject Ҏ写入中。而ObjectOutputStream 则通过 writeObject Ҏ为每个写入流中的对象Q包含所写对象所引用的对象)调用 replaceObject Ҏ。RMIObjectOutputStream子类?nbsp;replaceObject Ҏq回下列| 
如果传给 replaceObject 的对象是 java.rmi.Remote 的实例,则返回远E对象的 stub E序。远E对象的 stub E序通过对java.rmi.server.RemoteObject.toStubҎ的调用而获得。如果传l?nbsp;replaceObject 的对象不?nbsp;java.rmi.Remote 的实例,则只q回该对象?nbsp;

    RMI ?nbsp;ObjectOutputStream 子类也实?nbsp;annotateClass ҎQ该Ҏ用类的位|注解调用流以便能在接收器中下蝲该类。有兛_何?nbsp;annotateClass的详l信息,参见“动态类加蝲”一节。因为参数只写入一?nbsp;ObjectOutputStreamQ所以指向调用程序同一对象的引用将在接收器那里指向该对象的同一副本。在接收器上Q参数将被单个ObjectInputStream 所d?nbsp;

    用于写对象的 ObjectOutputStreamQ类似的q有用于d象的ObjectInputStream Q的所有其它缺省行为将保留在参C递中。例如,写对象时?nbsp;writeReplace 的调用及d象时?nbsp;readResolve 的调用就是由 RMI的参数编l与解编完成的?nbsp;

    与上q?nbsp;RMI 参数传递方式类|q回|或异常)被写入ObjectOutputStream的子cdƈ和参C输的替代行ؓ相同?nbsp;

定位q程对象 

    我们专门提供了一U简单的引导名字服务器,用于存储对远E对象的已命名引用。用类 java.rmi.Naming 的基?nbsp;URL 的方法可以存储远E对象引用。客h要调用远E对象的ҎQ则必须首先得到该对象的引用。对q程对象的引用通常是在Ҏ调用中以q回值的形式取得。RMI pȝ提供一U简单的引导名字服务器,通过它得到给定主Z的远E对象。java.rmi.Naming cL供基于统一资源定位W?nbsp;(URL) 的方法,用来l定、再l定、解开和列Z于某一L及端口上的名?对象寏V?nbsp;
 

TrampEagle 2006-01-19 11:33 发表评论
]]>
漫谈EJB (一)http://m.tkk7.com/TrampEagle/articles/28633.htmlTrampEagleTrampEagleThu, 19 Jan 2006 03:30:00 GMThttp://m.tkk7.com/TrampEagle/articles/28633.htmlhttp://m.tkk7.com/TrampEagle/comments/28633.htmlhttp://m.tkk7.com/TrampEagle/articles/28633.html#Feedback0http://m.tkk7.com/TrampEagle/comments/commentRss/28633.htmlhttp://m.tkk7.com/TrampEagle/services/trackbacks/28633.html引自Q?A 已经成ؓ服务器运环境的标准。Java Servlets、JSPQJava ServerPagesQ、EJBQEnterprise JavaBeansQ、JavaMail、JDBC、JMS{,都是各家厂商产品开发的重点方向。J2EE兼容的是一般Intel个h计算机(Linux、Windows.....Q、麦金塔以及各家高效能高E_度的UNIX伺服LQ未来必定成为服务器q算市场上的主要选择之一?BR>
    除了以上q三大Javal合之外QJava和XML的整合也是未来的重点。Sun公司已经推出Java处理XML的标准g伸API - Java API for XML Parsing (JAXP)Q可以让各家所制作的XML解析器有接口上的标准。所以在JavaE序中,只要了解一套API(JAXP)可以完全处理XML文gQ让XML的应用更加方ѝJavaq个跨^台的开发环境,加上XMLq个跨^台的资料格式Q此U跨q_优势l合势将成ؓ未来讯息传递及资料交换的主要应用技术,如虎ȝ地结合成一个最佳的跨^台解x案?BR>
    藉由J2SE (Java 2 Standard Edition)可以开发在PC上的应用软gQ藉由J2ME (Java 2 Micro Edition) 可以跨更广大的家电、智能卡、电子装|等市场Q再藉由J2EE (Java 2 Enterprise Edition ) 可以整合伺服Lq算环境。Java技术的应用范围几乎已经无所不在QJava技术更可以在网际网l及电子商务各领域中Q提供全方位的解x案?BR>
    随着应用领域的不同,Java 有许?nbsp;APIQApplication Programming InterfaceQ,q些 API 分成三大c:

    · Java Core APIQ由 Sun 制定的基?nbsp;APIQQ?nbsp;Java q_都必L供?nbsp;

    · Java Standard Extension API (javax)Q由 Sun 制定的扩?nbsp;APIQJava q_可以选择性地提供或加装?BR>
    · 厂商或组l所提供?nbsp;APIQ由各家公司或组l所提供?nbsp;

    其中 Core API ?nbsp;Standard Extension API 已经逐渐늛了大部䆾的信息应用领域,例如多媒体、数据库、Web、企业运、语韟뀁实时系l、网l、电话、媄像处理、加解密、GUI、分布式q算 ......。如果你有某w求尚未有标准?nbsp;Java API 可遵循,你可以向 Sun 提出制定?nbsp;API 的请求。经q审怹后,你的要求可能会通过、驳?nbsp;...... {。如果通过Q就会开始进入制?nbsp;API 的程序。Java API 的制定过E因为公开Q且l过许多业界技术领先公司的共同参与Q所以相当完善而优异?BR>

EJB的生态环?BR>
在sun公司提供的EJB规范中,我们一个完整的ZEJB的分布式计算l构由六个角色组成,q六个角色可以由不同的开发商提供Q每个角色所作的工作必须遵@Sun公司提供的EJB规范Q以保证彼此之间的兼Ҏ?BR>

    EJBlg开发? 开发ƈ销?nbsp;EJB?BR>    应用l合? 不同的 EJB 搭徏成应用?BR>    部v? 使用相应工具在运行环境下配置 EJB?BR>    EJB 服务器提供? 开发ƈ销?nbsp;EJB 服务?nbsp;
    EJB 容器供应? 开发ƈ销?nbsp;EJB 容器 
    pȝ理? 监视q行时情?BR>
    1、EJBlg开发?Enterprise Bean Provider)

    EJBlg开发者负责开发执行商业逻辑规则的EJBlgQ开发出的EJBlg打包成ejb-jar文g。EJBlg开发者负责定义EJB的remote和home接口Q编写执行商业逻辑的EJB class,提供部vEJB的部|文?deployment descriptor)。部|文件包含EJB的名字,EJB用到的资源配|,如JDBC{。EJBlg开发者是典型的商业应用开发领域专家?BR>
    EJBlg开发者不需要精通系l的编E,因此Q不需要知道一些系l的处理细节,如事务、同步、安全、分布式计算{?BR>
    2、应用组合?Application Assembler)

    应用l合者负责利用各UEJBl合一个完整的应用pȝ。应用组合者有旉要提供一些相关的E序Q如在一个电子商务系l里Q应用组合者需要提供JSP(Java Server Page)E序?BR>
    应用l合者必L握所用的EJB的home和remote接口Q但不需要知道这些接口的实现?BR>
    3、部|?Deployer)

    部v者负责将ejb-jar文g部v到用Lpȝ环境中。系l环境包含某UEJB Server和EJB Container。部|者必M证所有由EJBlg开发者在部v文g中声明的资源可用Q例如,部v者必配|好EJB所需的数据库资源?BR>
    部vq程分两步:部v者首先利用EJB Container提供的工L成一些类和接口,使EJB Container能够利用q些cd接口在运行状态管理EJB?nbsp;部v者安装EJBlg和其他在上一步生成的cdEJB Container中?nbsp;部v者是某个EJBq行环境的专家?BR>
    某些情况下,部v者在部v时还需要了解EJB包含的业务方法,以便在部|完成后Q写一些简单的E序试?BR>
    4、EJB 服务器提供?EJB Server Provider)

    EJB 服务器提供者是pȝ领域的专Ӟ_N分布式交易理Q分布式对象理及其它系l的服务。EJB 服务器提供者一般由操作pȝ开发商、中间g开发商或数据库开发商提供?BR>
    在目前的EJB规范中,假定EJB 服务器提供者和EJB 容器提供者来自同一个开发商Q所以,没有定义EJB 服务器提供者和EJB容器提供者之间的接口标准?BR>
    5、EJB 容器提供?EJB Container Provider)

    EJB 容器提供者提供以下功能:

    提供EJB部v工具为部|好的EJBlg提供q行环境 。EJB容器负责为EJB提供交易理Q安全管理等服务?BR>
    EJB 容器提供者必LpȝU的~程专家Q还要具备一些应用领域的l验。EJB 容器提供者的工作主要集中在开发一个可伸羃的,h交易理功能的集成在EJB 服务器中的容器。EJB 容器提供者ؓEJBlg开发者提供了一l标准的、易用的API讉KEJB 容器QEJBlg开发者不需要了解EJB服务器中的各U技术细节?BR>
    EJB容器提供者负责提供系l监工L来实时监EJB容器和运行在容器中的EJBlg状态?BR>
    6、系l管理员(System Administrator)

    pȝ理员负责ؓEJB服务器和容器提供一个企业的计和|络环境?BR>
    pȝ理员负责利用EJB 服务器和容器提供的监管理工LEJBlg的运行情c?BR>
    责dȝ另一个好处是在代码上,可以基于EJBs的系l逻辑的分z更适合的专家。SUN的EJB规范使用几个独立的角Ԍ对于定q作环境的责任链是非帔R要的。D例说QEJB提供者是由商业专家和分析人员扮演的角Ԍ他们定一个组l内的最佳信息流E。但是仍旧有Second Domain ExpertQ如应用E序汇编人员Q他们集成不同的EJBlgq确保它可以保满应用E序的需求?BR>
    q有两种角色归入到系l的部分,W一个是配置人员Q他们负责实际的安装和配|基于EJB的系l。这需要有讄目录服务和集成现有应用程序的l验。第二个是系l管理员Q他们要提供全天的监视和支持Q确保应用程序正常运作。尽系l管理员q个角色不需要是Java~程专家Q但是他需要能够应付以下问题:

    讄Java Virtual Machine (JVM)q关联系l环境参敎ͼ如:CLASSPATHQ?nbsp;
    使用Java Archive (jar)命o保存cL?nbsp;
    懂得WEB服务器和Servlet的工作原理?nbsp;
    要能通过监视q行中程序的状态确定优化方法?nbsp;

    很明显,有些角色是可以交叉的Q比如系l管理员和配|h员。尽配|h员可能是类文g复制到服务器而系l管理员需要确定配|h员是否复制到了正的位置?nbsp;



TrampEagle 2006-01-19 11:30 发表评论
]]>
《EJB调用的原理分析?/title><link>http://m.tkk7.com/TrampEagle/articles/27366.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 10 Jan 2006 05:10:00 GMT</pubDate><guid>http://m.tkk7.com/TrampEagle/articles/27366.html</guid><wfw:comment>http://m.tkk7.com/TrampEagle/comments/27366.html</wfw:comment><comments>http://m.tkk7.com/TrampEagle/articles/27366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/TrampEagle/comments/commentRss/27366.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/TrampEagle/services/trackbacks/27366.html</trackback:ping><description><![CDATA[<span id="uwrkvza" class=postbody>引自Q?A >http://forum.javaeye.com/viewtopic.php?t=1036</A><BR><BR>一个远E对象至要包括4个class文gQ远E对象;q程对象的接口;实现q程接口的对象的stubQ对象的skeletonq?个class文g?<BR><BR>在EJB中则臛_要包?0个classQ?<BR>Beanc,特定App Server的Bean实现c?<BR>Bean的remote接口Q特定App Server的remote接口实现c,特定App Server的remote接口的实现类的stubcdskeletonc?<BR>Bean的home接口Q特定App Server的home接口实现c,特定App Server的home接口的实现类的stubcdskeletonc?<BR><BR>和RMI不同的是QEJB中这10个class真正需要用L写的只有3个,分别是Beancd它的remote接口Qhome接口Q至于其它的7个class到底是怎么生成Q被打包在什么地方,或者是否需要更多的cLӞ会根据不同的App Server表现出比较大的差异,不能一概而论?<BR><BR>拿我最熟悉的Weblogic的来说吧QWeblogic的Bean实现c,以及两个接口的Weblogic的实现类是在ejbc的时候被打包到EJB的jar包里面的Q这3个class文g可以看到。而home接口和remote接口的Weblogic的实现类的stubcdskeletoncL在EJB被部|到Weblogic的时候,由Weblogic动态生成stubcdSkeletoncȝ字节码,因此看不到这4个类文g?<BR><BR>对于一ơ客Lq程调用EJBQ要l过两个q程对象的多ơRMI循环。首先是通过JNDI查找Home接口Q获得Home接口的实现类Q这个过E其实相当复杂,首先是找到Home接口的Weblogic实现c,然后创徏一个Home接口的Weblogic实现cȝstubcȝ对象实例Q将它序列化传送给客户端(注意stubcȝ实例是在W?ơRMI循环中,由服务器动态发送给客户端的Q因此不需要客L保存Home接口的Weblogic实现cȝstubc)Q最后客L获得该stubcȝ对象实例Q普通的RMI需要在客户端保存stubc,而EJB不需要,因ؓ服务器会把stubcȝ对象实例发送给客户端)?<BR><BR>客户端拿到服务器l它的Home接口的Weblogic实现cȝstubcd象实例以后,调用stubcȝcreateҎQ?在代码上是home.create()Q但是后台要做很多事?,于是l过W?ơRMI循环Q在服务器端QHome接口的Weblogic实现cȝskeletoncL到stubcȝ调用信息后,由它再去调用Home接口的Weblogic实现cȝcreateҎ?<BR><BR>在服务端QHome接口的Weblogic实现cȝcreateҎ再去调用BeancȝWeblogic实现cȝejbCreateҎQ在服务端创建或者分配一个EJB实例Q然后将q个EJB实例的远E接口的Weblogic实现cȝstubcd象实例序列化发送给客户端?<BR><BR>客户端收到remote接口的Weblogic实现cȝstubcȝ对象实例Q对该对象实例的Ҏ调用Q在客户端代码中实际上就是对remote接口的调用)Q将传送给服务器端remote接口的Weblogic实现cȝskeletoncd象,而skeletoncd象再调用相应的remote接口的Weblogic实现c,然后remote接口的Weblogic实现cd去调用BeancȝWeblogic实现c,如此完成一ơEJB对象的远E调用?<BR><BR>看了一遍帖子,感觉q是没有说太清楚Q既然写了帖子,想d把它说清楚?<BR><BR>先拿普通RMI来说Q有4个classQ分别是q程对象Q对象的接口Q对象的stubcdskeletoncR而对象本w和对象的stubcd旉实现了接口类。而我们在客户端代码调用远E对象的时候,虽然在代码中操纵接口Q实质上是在操纵stubc,例如Q?<BR>接口c:Hello <BR>q程对象QHello_Server <BR>stubc:Hello_Stub <BR>skeletonc:Hello_Skeleton <BR><BR>客户端代码要q样写: <BR>Hello h = new Hello_Stub(); <BR>h.getString(); <BR><BR>我们不会q些写: <BR>Hello_Stub h = new Hello_Stub(); <BR>h.getString(); <BR><BR>因ؓ使用接口适用性更q,q更换了接口实现类Q也不需要更改代码。因此客L需要Hello.class和Hello_Stub.classq两个文件。但是对于EJB来说Q就不需要Hello_Stub.classQ因为服务器会发送给它,但是Hello.class文g客户端是省不了的Q必L。表面上我们的客L代码在操UHelloQ但别忘CHello只是一个接口,抽象的,实质上是在操UHello_Stub?<BR><BR>拿Weblogic上的EJB举例子,10个class分别是: <BR>Beanc:HelloBean Q用L写) <BR>BeancȝWeblogic实现c:HelloBean_Impl QEJBC生成Q?<BR><BR>Home接口QHelloHome Q用L写) <BR>Home接口的Weblogic实现c?HelloBean_HomeImplQEJBC生成Q?<BR>Home接口的Weblogic实现cȝstubc?HelloBean_HomeImpl_WLStubQ部|的时候动态生成字节码Q?<BR>Home接口的Weblogic实现cȝskeletonc?HelloBean_HomeImpl_WLSkeletonQ部|的时候动态生成字节码Q?<BR><BR>Remote接口Q?Hello Q用L写) <BR>Remote接口的Weblogic实现c?HelloBean_EOImplQEJBC生成Q?<BR>Remote接口的Weblogic实现cȝstubc?HelloBean_EOImpl_WLStubQ部|的时候动态生成字节码Q?<BR>Remote接口的Weblogic实现cȝskeletonc?HelloBean_EOImpl_WLSkeletonQ部|的时候动态生成字节码Q?<BR><BR>客户端只需要Hello.class和HelloHome.classq两个文件?<BR><BR>HelloHome home = (Home) PortableRemoteObject.narrow(ctx.lookup("Hello"), HelloHome.class); <BR><BR>q一行代码是从JNDI获得Home接口Q但是请CQ接口是抽象的,那么homeq个对象到底是什么类的对象实例呢Q很单,用toString()输出看一下就明白了,下面一行是输出l果Q?<BR>HelloBean_HomeImpl_WLStub@18c458 <BR>q表明homeq个通过从服务器的JNDI树上查找获得的对象实际上是HelloBean_HomeImpl_WLStubcȝ一个实例?<BR>接下来客L代码Q?<BR><BR>Hello h = home.create() <BR><BR>同样Hello只是一个抽象的接口Q那么h对象是什么东西呢Q打C下: <BR>HelloBean_EOImpl_WLStub@8fa0d1 <BR>原来是HelloBean_EOImpl_WLStub的一个对象实例?<BR><BR>用这个例子来qC遍EJB调用q程Q?<BR><BR>首先客户端JNDI查询Q服务端JNDI树上Helloq个名字实际上绑定的对象是HelloBean_HomeImpl_WLStubQ所以服务端创建HelloBean_HomeImpl_WLStub的一个对象实例,序列化返回给客户端?<BR><BR>于是客户端得到home对象Q表面上是得到HelloHome接口的实例,实际上是q行了一ơ远E调用得CHelloBean_HomeImpl_WLStubcȝ对象实例Q别忘记了HelloBean_HomeImpl_WLStub也实CHelloHome接口?<BR><BR>然后home.create()实质上就是HelloBean_HomeImpl_WLStub.create()Q该Ҏ发送信息给HelloBean_HomeImpl_WLSkeletonQ而HelloBean_HomeImpl_WLSkeleton接受C息后Q再去调用HelloBean_HomeImpl的createҎQ至此完成第1ơ完整的RMI循环?<BR><BR>注意在这ơRMI循环q程中,q程对象是HelloBean_HomeImplQ远E对象的接口是HelloHomeQ对象的stub是HelloBean_HomeImpl_WLStubQ对象的skeleton是HelloBean_HomeImpl_WLSkeleton?<BR><BR>然后HelloBean_HomeImpl再去调用HelloBean_Impl的ejbCreateҎQ而HelloBean_Impl的ejbCreateҎ负责创建或者分配一个Bean实例Qƈ且创Z个HelloBean_EOImpl_WLStub的对象实例?<BR><BR>q一步比较有的是,在前一步RMI循环中,q程对象HelloBean_HomeImpl在客L有一个代理类HelloBean_HomeImpl_WLStubQ但在这一步,HelloBean_HomeImpl自己却充当了HelloBean_Impl的代理类Q只不过HelloBean_HomeImpl不在客户端,而是在服务端Q因此不q行RMI?<BR><BR>然后HelloBean_EOImpl_WLStub的对象实例序列化q回l客LQ这一步也很有,上次RMIq程Q主角是HelloBean_HomeImpl和它的代理类HelloBean_HomeImpl_WLStubQ但q这一ơ换成了HelloBean_EOImpl和它的代理类HelloBean_EOImpl_WLStub来玩了?<BR><BR><BR>Hello h = home.create();h.helloWorld(); <BR><BR>假设Hello接口有一个helloWorldq程ҎQ那么表面上是在调用Hello接口的helloWorldҎQ实际上是在调用HelloBean_EOImpl_WLStub的helloWorldҎ?<BR><BR>然后HelloBean_EOImpl_WLStub的helloWorldҎ发送信息给服务器上的HelloBean_EOImpl_WLSkeletonQ而HelloBean_EOImpl_WLSkeleton收到信息以后Q再去调用HelloBean_EOImpl的helloWorldҎ。至此,完成W?ơ完整的RMI循环q程?<BR><BR>在刚才HelloBean_EOImpl是作E对象被调用的,它的代理cLHelloBean_EOImpl_WLStubQ但现在HelloBean_EOImpl要作为HelloBean_Impl的代理类了。现在HelloBean_EOImpl去调用HelloBean_Impl的helloWorldҎ。注意!HelloBean_Impll承了HelloBeanQ而HelloBean中的helloWorldҎ是我们亲自编写的代码Q现在终于调用到了我们编写的代码了! <BR><BR>xQ一ơEJB调用q程l于完成。在整个q程中,服务端主要要调用的类是HelloBean_ImplQ?HelloBean_HomeImplQHelloBean_HomeImpl_WLSkeletonQHelloBean_EOImplQHelloBean_EOImpl_WLSkeleton。客L主要调用的类是HelloBean_HomeImpl_WLStubQHelloBean_EOImpl_WLStubQ这两个cd客户端代码中q不会直接出玎ͼ出现在代码中的类是他们的接口HelloHome和HelloQ因此客L需要这两个接口文gQ而Stub是服务器传送给他们的?/SPAN><img src ="http://m.tkk7.com/TrampEagle/aggbug/27366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-10 13:10 <a href="http://m.tkk7.com/TrampEagle/articles/27366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://m.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://9hao66.com" target="_blank">վ߹ۿ</a>| <a href="http://bjyaao.com" target="_blank">þþƷѹۿ</a>| <a href="http://simupiao.com" target="_blank">18ڵվ</a>| <a href="http://www759696b.com" target="_blank">avպav߹ۿ</a>| <a href="http://9988u.com" target="_blank">þþƷƵ</a>| <a href="http://19520888.com" target="_blank">þ޾Ʒ777С˵</a>| <a href="http://www52a.com" target="_blank">۲ӰԺ߲wwwѹۿ</a>| <a href="http://o091i.com" target="_blank">AVרAV԰</a>| <a href="http://wwwy6x22.com" target="_blank">ҹƷһƵ</a>| <a href="http://mottool.com" target="_blank">޹һaëƬ</a>| <a href="http://5079157.com" target="_blank">߾ƷaaaƬ</a>| <a href="http://youweidianqi.com" target="_blank">ձ޳ɸһ</a>| <a href="http://yy12345.com" target="_blank">avѸ߳ˮ</a>| <a href="http://hubmba.com" target="_blank">þþþþ޾ƷĻ</a>| <a href="http://bzzxyp.com" target="_blank">re99þ6Ʒ</a>| <a href="http://828556.com" target="_blank">޾ƷĻ</a>| <a href="http://456qqq.com" target="_blank">24Сʱձwwwѵ</a>| <a href="http://234an.com" target="_blank">avרҳ</a>| <a href="http://wwkk3.com" target="_blank">޾ƷVƬ߹ۿ</a>| <a href="http://sswg2.com" target="_blank">91Ƶ</a>| <a href="http://www907ii.com" target="_blank">˳߲վ</a>| <a href="http://3c3w.com" target="_blank">þòþüĻ</a>| <a href="http://xixidhw.com" target="_blank">޾Ʒ߾ƷƵ </a>| <a href="http://zfjhw.com" target="_blank">www߹ۿƵ</a>| <a href="http://gisdn.com" target="_blank">gv޹gvո</a>| <a href="http://by1687.com" target="_blank">պѵƵ߹ۿ㽶</a>| <a href="http://avqvod.com" target="_blank">ŮƷƵ</a>| <a href="http://gw311.com" target="_blank">Ůǿ߳վ</a>| <a href="http://97aimeili.com" target="_blank">һƵ</a>| <a href="http://359777b.com" target="_blank">޹һӰ</a>| <a href="http://fenxiangceo.com" target="_blank">վ߹ۿ</a>| <a href="http://vastraje.com" target="_blank">ɫŮ18ŮëƬƵ</a>| <a href="http://szgyk.com" target="_blank">޳AVƬ߹ۿ</a>| <a href="http://sswg2.com" target="_blank">ɫƵվ</a>| <a href="http://kencery.com" target="_blank">͵Ƶ߹ۿ99</a>| <a href="http://cc45987.com" target="_blank">avרavһ</a>| <a href="http://h47h.com" target="_blank">97޳ҹҹ</a>| <a href="http://wenfaka.com" target="_blank">˿Ƶ</a>| <a href="http://rhacu.com" target="_blank">һþ</a>| <a href="http://njjngs.com" target="_blank">С˵ͼƬ</a>| <a href="http://5gz0z.com" target="_blank">þó˹Ʒ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>