随笔-159  评论-114  文章-7  trackbacks-0
为了解决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

rmi2.jpg

===============================

开始分析EJB工作原理

看下面一张图,就清楚了,实际就是两次RMI 调用。

27229257.ejb2.jpg

要细致来说。

基本是这样的。

定义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)  编辑  收藏 所属分类: 达内学习总结

只有注册用户登录后才能发表评论。


网站导航: