为了解决RMI无法解决的分布式事务控制,安全,并发等问题。
EJB解决访问就是一种可以高校的开发分布式应用的解决方案。
编写EJB,其实只需要编写2个接口和一个Bean类,和一个部属描述就可以了。
服务接口:
import javax.ejb.*;
import java.rmi.*;
//business remote
public interface Compute extends EJBObject{
public double add(double a,double b) throws RemoteException;
}
Home接口:
import javax.ejb.*;
import java.rmi.*;
public interface ComputeHome extends EJBHome{
public Compute create() throws RemoteException,CreateException;
} Bean,业务逻辑实现的地方
import javax.ejb.*;
public class ComputeBean implements SessionBean
{
public void setSessionContext(SessionContext ctx)
throws EJBException,
java.rmi.RemoteException{
}
public void ejbRemove()
throws EJBException,
java.rmi.RemoteException{
}
public void ejbActivate()
throws EJBException,
java.rmi.RemoteException{
}
public void ejbPassivate()
throws EJBException,
java.rmi.RemoteException{
}
public void ejbCreate() throws CreateException{
}
public double add(double a,double b){
return a*b;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<display-name>Compute</display-name>
<ejb-name>abc</ejb-name>
<home>ComputeHome</home>
<remote>Compute</remote>
<ejb-class>ComputeBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>abc</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar> JNDI的实现各个服务器的实现不同,所以需要依赖于服务器的一个xml。
JNDI也是一种面向接口编程,工厂模式的典范。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>abc</ejb-name>
<jndi-name>efg</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
想编译EJB,需要j2ee jar,那就用\bea\weblogic81\server\lib\weblogic.jar
做一个META-INF放置两个xml文件
jar -cvf Compute.jar *.class META-INF/*.xml
c创建,v看到它创建的过程,f文件名
部属EJB,看看Weblogic帮助吧。
=============================
那么会发现jar文件中并没有出现_stub或者_skeleton文件阿,那是因为由容器在运行EJB时动态创建在容器内部了。
那么怎么才能看到呢?我们要分析阿。
java weblogic.appc ejb.jar
如果抱错,在classpath中添加\jdk142_04\lib\tools.jar
如果想看原文件的话,就是-keepgenerated
===============================
开始分析EJB工作原理
看下面一张图,就清楚了,实际就是两次RMI 调用。
要细致来说。
基本是这样的。
定义Home接口,主要是为让客户端有可能在创建EJB Bean对象时,给予初始化。
import javax.ejb.*;
import java.rmi.*;
public interface ComputeHome extends EJBHome{
public Compute create() throws RemoteException,CreateException;
}
这只是一个接口,weblogic.appc会生成一个HomeImpl,并生成Stub和Skeleton对象。在客户端JNDI查找时,返回就是这个HomeImpl的Stub对象,注意类文件也会动态下载的。
create()与ejbcreate()方法是对应的。
可有参数。
//Bean
public void ejbCreate(String param) throws CreateException {
// TODO Auto-generated method stub
this.userName = param;
}
//Home
public com.infogo.interfaces.Shopping create(java.lang.String param)
throws javax.ejb.CreateException,java.rmi.RemoteException; ===========
那么客户端实际调用的是HomeImpl的Stub对象的方法,通过网络传送到服务器上的Skeleton,Skeleton再调用真正的HomeImpl对象的方法,创建一个创建Bean对象放入实例池,Impl调用Bean的ejbcreate方法,初始化参数。
并且HomeImpl,还要创建一个业务业务接口的实现类,并把业务接口实现类(EOImpl)对象的Stub返回给客户端。
客户端拿到Stub,调用响应服务方法(别忘了,真正的服务方法实现可是在Bean类里),所以调用Stub方法,通过网络传递EOImpl的Skeleton对象,然后调用EOImpl的响应方法。
这是注意,EOImpl被称为请求拦截器,因为它会在这时察看ejb-jar.xml,看一看方法声明的事务类型,并调用容器提供的API(安全、事务等)。所以这种服务器或者容器叫做隐式容器,它有工具生成的类来调用容器相关API。而不是用户直接调用。
在EOImpl调用完容器API之后,就会调用Bean的业务方法。
最后将接口-Skeleton-Stub-客户端。
所以是两次RMI调用。
这就是EJB工作原理。
import javax.naming.*;
import java.util.*;
import javax.rmi.*;
public class Client
{
public static void main(String[] args) throws Exception
{
Hashtable hash = new Hashtable();
hash.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
InitialContext ic = new InitialContext(hash);
ComputeHome home = (ComputeHome)ic.lookup("efg");
//(ComputeHome)ProtableRemoteObject.narrow(ic.lookup("efg"),ComputeHome.class);
/**//*
* 客户端从服务器获得HomeImpl_stub .class文件,并获得HomeImpl_stub的对象
*
* home.create()-->HomeImpl_stub.create()-->网络发送-->HomeImpl_skel.create()-->HomeImpl创建ComputeBean对象-->ComputeBean.ejbcreate()&&HomeImpl还要创建EOImpl_stub对象,返回HomeImpl_skel--->[网络往回传输]--->HomeImpl_stub--->客户端拿到EOImpl_stub对象。
*
* 这时完成了第一次rmi
*
* c获得了EOImpl_Stub对象,
*
* c.add(32,32)----> EOImpl_Stub.add()--->网络发送--->EOImpl_Skel.add()--->EOImpl--->[根据xml描述的事务,进行事务描述]--->判断add方法是否开始事务--->调用创建好Bean对象的add方法---->方法结果给EOImpl_Skel---->网络往回传输---->EOImpl_Stub----客户端拿到结果。
*
* 第二次rmi完成。
*/
Compute c = home.create();
System.out.println(c.add(32,32));
}
}
posted on 2006-03-19 23:45
北国狼人的BloG 阅读(967)
评论(0) 编辑 收藏 所属分类:
达内学习总结