kapok

          垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks
          http://blog.csdn.net/stripbolt/archive/2004/10/24/149705.aspx

          JBoss是一個非常優秀的J2EE的Application Server,研究
          它的源代碼有助于我們更好的理解J2EE的各種技術。
          本系列擬從四個方面分析Jboss源碼:
          1.EJB Container實現
          2.Transaction實現
          3.Persistence Mapping
          4.Client到Server端的Invocation

          -------------------------------------------------------------------
          先說第1點:EJB Container實現。
          1.1 EJB Pool
          我們知道,EJB Container 會維護一個EJB池,
          在多個client間共享,避免頻繁創建銷毀對象的開銷。
          讓我們來看看Jboss實現的Pool:
          EJB分EntityBean,MDB,Stateless/Stateful Session Bean,
          而Jboss中也對應的有EntityInstancePool,MessageDrivenInstancePool,
          StatefulSessionInstancePool,StatelessSessionInstancePool.
          讓我們先從這4個類的共同基類AbstractInstancePool看起:
          class AbstractInstancePool實現了接口InstancePool,該接口有以下幾個方法:
          EnterpriseContext get() throws Exception;
          void free(EnterpriseContext ctx);
          void discard(EnterpriseContext ctx);
          int getCurrentSize();
          public int getMaxSize();
          --------------------------------------------------------------------
          先對EnterpriseContext作番說明。EnterpriseContext的作用
          就是把具體的EJB instance和它的metadata聯系起來。
          該類簽名為:
          public abstract class EnterpriseContext,
          有4個子類,EntityEnterpriseContext,MessageDrivenEnterpriseContext,
          StatefulSessionEnterpriseContext,StatelessSessionEnterpriseContext。
          分別對應4種類型的EJB。
          EnterpriseContext中有幾個重要的成員變量。
          /** The EJB instance */
          Object instance;
          /** The container using this context */
          Container con; //Container這個類是JBoss用來代表對EJB提供Transaction,Security,Pool等服務的類,我們回頭還會再說。
          /** Only StatelessSession beans have no Id, stateful and entity do */
          Object id;

          /** The transaction associated with the instance */
          Transaction transaction; //Transaction,我們下節再說.

          // Constructors --------------------------------------------------

          public EnterpriseContext(Object instance, Container con)
          {
          this.instance = instance;
          this.con = con;
          }

          public Object getInstance()
          {
          return instance;
          }
          public Container getContainer() {
          return con;
          }

          public void setId(Object id) {
          this.id = id;
          }

          public Object getId() {
          return id;
          }

          public void setTransaction(Transaction transaction) {
          this.transaction = transaction;
          }

          public Transaction getTransaction() {
          return transaction;
          }

          /**
          * Get the EJBContext object
          */
          public abstract EJBContext getEJBContext(); //由子類實現

          //返回javax.ejb.EJBContext,注意這個EJBContext是
          EJB規范要求提供給EJB的Context,與JBoss自己實現類EnterpriseContext沒有關系。

          /** The instance is being used. This locks it\'s state */
          int locked = 0;
          public void lock()
          {
          locked ++;
          }

          public void unlock() {
          locked --;
          }

          public boolean isLocked() {
          return locked != 0;
          }
          //lock這個成員變量表示當前這個EJB instance有沒人在用。
          //這個變量用來給Reentrance,以及canPassviate用.
          /**
          * before reusing this context we clear it of previous state called
          * by pool.free()
          * 從pool里取出來的時候沒有關聯任何EJB instance和Transaction信息
          * 在返還pool的時候把這些信息清掉。
          */
          public void clear() {
          this.id = null;
          this.locked = 0;
          this.transaction = null;
          }
          //-------------------------------------------------------------------------------------
          protected boolean isContainerManagedTx()
          {
          BeanMetaData md = (BeanMetaData)con.getBeanMetaData();
          return md.isContainerManagedTx();
          }
          //從關聯的container拿出對應的metadata,判斷是否CMT.
          //注意這里con是Container成員變量,可不是什么連接,連接一般縮寫為conn,
          //我一開始就搞混了:)
          //BeanMetaData這些MetaData的子類都是從xml配置里頭讀出來的Metadata構造的,
          //沒什么神秘的.
          這個類里頭還有兩個inner class,EJBContextImpl implements EJBContext,
          UserTransactionImpl implements UserTransaction。EJBContextImpl等
          講解過Container再說,UserTransaction等下節再說。

          現在讓我們來看看EnterpriseContext的幾個子類:
          首先類比一下幾個子類的成員變量:
          EntityEnterpriseContext:
          private EJBObject ejbObject;
          private EJBLocalObject ejbLocalObject;
          private EntityContext ctx;

          StatefulSessionEnterpriseContext
          private EJBObject ejbObject;
          private EJBLocalObject ejbLocalObject;
          private SessionContext ctx;

          StatelessSessionEnterpriseContext
          EJBObject ejbObject;
          EJBLocalObject ejbLocalObject;
          SessionContext ctx;

          MessageDrivenEnterpriseContext:
          private MessageDrivenContext ctx;
          看來除了MDB沒有對應的EJBObject/EJBLocalObject,其他統統都有:)
          學過EJB的人都知道,在語法上EJB instance 是implements
          EntityBean/SessionBean/MessageDrivenBean (這3個interface有一個共同的
          interface: public interface EnterpriseBean extends Serializable,
          EnterpriseBean 是個Marker接口,里頭什么都沒有,好像Serializable接口一樣,只說明
          實現它的是個EJB.而EntityBean/SessionBean/MessageDrivenBean 有對應的
          void ejbActivate() throws EJBException, RemoteException;
          void ejbLoad() throws EJBException, RemoteException;
          一些方法需要實現。(雖然常常是空實現:),由容器作了很多事)
          至于EJBObject/EJBLocalObject 在語法上都是非直接實現的,代表EJB instance暴露出的Remote/Local 接口。既然這些EJB instance非直接實現這些接口,那么這些接口如何與具體的EJB instance相關聯,我們講到Container類時就知道了。
          ----------------------------------------------------------------------------------


          EnterpriseContext的子類EntityEnterpriseContext的構造函數
          public EntityEnterpriseContext(Object instance, Container con)
          throws RemoteException
          {
          super(instance, con);
          ctx = new EntityContextImpl(); //這是EJBContextImpl的子類,不急著說:)
          ((EntityBean)instance).setEntityContext(ctx);//看看,原來set...Context是在這里調用的//其它instance實現的什么ejbCreate(),EJBLoad,EJBActive()到底是什么時候
          調用的呢?接下來我們慢慢找,這可散布在各地呢:)
          }
          //其他幾個子類的構造函數前3行也都如此,是類似的。
          對于StatelessSessionEnterpriseContext和MessageDrivenEnterpriseContext,緊接的是

          Method ejbCreate = instance.getClass().getMethod(\"ejbCreate\", new Class[0]);
          ejbCreate.invoke(instance, new Object[0]);
          //看看,來了一個ejbCreate:),對于StatelessSessionBean,一上來就ejbCreate()了~
          接下來看點簡單的:對于EnterpriseContext,
          有public abstract void discard() throws RemoteException;
          對于MessageDriven...的
          public void discard() throws RemoteException
          {
          ((MessageDrivenBean)instance).ejbRemove();
          }
          對于StatelessSession的
          public void discard() throws RemoteException
          {
          ((SessionBean)instance).ejbRemove();
          }
          對于StatefulSession...的
          public void discard() throws RemoteException
          {
          // Do nothing
          }
          對于Entity....
          public void discard() throws RemoteException
          {
          ((EntityBean)instance).unsetEntityContext();
          }
          //discard 是在AbstractInstancePool中的
          void discard(EnterpriseContext ctx);調用的

          /**
          * Discard an anonymous instance after invocation.
          * This is called if the instance should not be reused, perhaps due to some
          * exception being thrown from it.
          *
          * @param ctx The context to discard.
          */
          public void discard(EnterpriseContext ctx)
          {
          ctx.discard();
          }
          AbstractInstancePool還有個free方法:
          public void free(EnterpriseContext ctx) {
          ctx.clear();//記得ctx只是清掉id,transaction等,返回pool,準備復用么?
          //discard是在發生錯誤的時候,不希望擴大影響,于是discard掉,
          //而對應get()的free方法只是把EnterpriseContext返還給pool.
          }
          ----------------------------------------------------------------------------------

          專門對于Stateful....Context有設置EJB instance的函數
          /**
          * During activation of stateful session beans we replace the instance
          * by the one read from the file.
          */
          public void setInstance(Object instance)
          {
          this.instance = instance;
          ((SessionBean)instance).setSessionContext(ctx);
          }
          注意在4種...Context中,只有Stateful...Context簽名
          public class StatefulSessionEnterpriseContext
          extends EnterpriseContext
          implements Serializable
          多了個implements Serializable,(其他都沒有),
          這是為了支持Activation/Passviation,Passviation的時候
          把EJB Instance寫到文件中。
          在StatefulSessionEnterpriseContext中有這樣兩個方法
          private void writeObject(ObjectOutputStream out)
          throws IOException, ClassNotFoundException
          {
          // do nothing
          }

          private void readObject(ObjectInputStream in)
          throws IOException, ClassNotFoundException
          {
          // do nothing
          }
          //說明序列化的時候StatefulSessionEnterpriseContext本身不需要
          寫出什么狀態,只有對應的EJB instance才需要寫出狀態。
          現在來看AbstractInstancePool的源碼,由于內容太多
          就不詳細解釋了。

          先看Abstract...Pool的create(Object instance)函數熱熱身~
          Abstract...Pool
          // Protected -----------------------------------------------------
          protected abstract EnterpriseContext create(Object instance)
          throws Exception;
          對Entity...Pool
          protected EnterpriseContext create(Object instance)
          throws Exception
          {
          return new EntityEnterpriseContext(instance, getContainer());
          }
          其他3種Pool類似。
          再回頭看Abstract..Pool
          /** The pool data structure */
          protected EnterpriseContext[] pool;
          protected int currentIndex = -1;
          /** The maximum number of instances allowed in the pool */
          protected int maxSize = 30;
          /** The minimum size of the pool */
          protected int minSize = 0;
          /** determine if we reuse EnterpriseContext objects i.e. if we actually do pooling */
          protected boolean reclaim = false;//對于MDB和StatelessSessionBean,這個變量被設為true,// for MDB, we *do* pool // for SLSB, we *do* pool

          ok,現在來看pool的重頭戲,get()/free(EnterpriseContext ctx)函數
          (discard(EnterpriseContext ctx)前面講過,不再重復)
          這幾個函數也是Interface InstancePool里頭要實現的接口:)
          閑話少說,來看代碼~~
          protected boolean minSizeInitialized = false;


          /**
          * Get an instance without identity.
          * Can be used by finders,create-methods, and activation
          *
          * @return Context /w instance
          * @exception RemoteException
          */

          public EnterpriseContext get() {
          //pool里頭有東東就拿出來
          synchronized (pool)
          {
          if (currentIndex > -1)
          {
          EnterpriseContext ctx = pool[currentIndex];
          pool[currentIndex--] = null;
          return ctx;
          }
          }

          //initialize a small fixed size of instance at startup.
          if (!minSizeInitialized)
          {
          minSizeInitialized = true;
          synchronized (pool)
          {
          for (int i = 0; i < minSize; i++)
          {
          pool[++currentIndex] = create(container.createBeanClassInstance());
          }
          }
          }

          // Pool is empty, create an instance
          return create(container.createBeanClassInstance());
          }

          /**
          * Return an instance after invocation.
          *
          * Called in 2 cases:
          * a) Done with finder method
          * b) Just removed
          *
          * @param ctx
          */
          public void free(EnterpriseContext ctx) {
          ctx.clear();
          synchronized (pool)
          {
          if (currentIndex + 1 < maxSize)
          {
          pool[++currentIndex] = ctx;
          }
          }
          }
          對于Entity...Pool,他overwrite了free
          /**
          * Return an instance to the free pool. Reset state
          *
          *

          Called in 3 cases:
          *


            *
          • Done with finder method
            *
          • Removed
            *
          • Passivated
            *

          *
          * @param ctx
          */
          public void free(EnterpriseContext ctx)
          {
          // If transaction still present don\\\\\\\\\\\\\\\'t do anything (let the instance be GC)
          if (ctx.getTransaction() != null)
          {
          return ;
          }
          super.free(ctx);
          }

          -----------------------------------------------------
          而Stateful....Pool的free方法overwrite了Abstract...Pool的,
          public synchronized void free(EnterpriseContext ctx)
          {
          discard(ctx);//干脆就discard掉不用了~
          }

          剩下的下回再講,先預告2個類體系:
          1.AbstractInstanceCache ,有EntityInstanceCache和StatefulSessionInstanceCache 子類。對于Entity,用它的
          PrimaryKey作Cache的Key,對于Stateful,Jboss也會付給
          每個instance一個唯一標定的值用來做CacheKey.
          Abstract...Cache與Abstract...Pool結合使用,得到好的Performance。
          2.public abstract class Container,
          有EntityContainer,MessageDrivenContainer,Stateful/StatelessSessionContainer
          4個子類,用來提供對EJB instance的transaction/security/pool等服務。
          //看看它的成員變量,就能猜個大概
          /** This is the TransactionManager */
          protected TransactionManager tm;

          /** This is the SecurityManager */
          protected AuthenticationManager sm;

          /** This is the instancepool that is to be used */
          protected InstancePool instancePool;
           
          開始講Container,以前說過Container有4種子類,分別對應4種類型的EJB.
          一個Container是所有Container plugins(注1)和metadata(注2)的集散地,the container plugins可以從container拿到metadata和其他container plugins.EJB部署的時候會創建相應的Container.Container基本不做太多事,主要delegate給plugins作事情。
          ok,讓我們來看看Container的成員變量:
          /**
          * This is the new metadata. it includes information from both ejb-jar and
          * jboss.xml the metadata for the application can be accessed trough
          * metaData.getApplicationMetaData()
          */
          protected BeanMetaData metaData;

          /** This is the EnterpriseBean class */
          protected Class beanClass;

          /** This is the Home interface class */
          protected Class homeInterface;

          /** This is the Remote interface class */
          protected Class remoteInterface;

          /** The local home interface class */
          protected Class localHomeInterface;

          /** The local inteface class */
          protected Class localInterface;

          /** This is the TransactionManager */
          protected TransactionManager tm;

          /** This is the SecurityManager */
          protected AuthenticationManager sm;

          /** This is the realm mapping */
          protected RealmMapping rm;

          /** This is the bean lock manager that is to be used */
          protected BeanLockManager lockManager;

          /** This is the application that this container is a part of */
          protected EjbModule ejbModule;
          //ejbModule作為一個單元部署的Module,比如一個ejb-jar就是一個Module,
          /*這個 ejb-jar里頭可能有多個entitybean,sessionbean,那么對于 每個entitybean,sessionbean
          都會有一個對應的container,而這些東東共享一個ejbModule.*/
          /**
          * Returns a new instance of the bean class or a subclass of the bean class.
          * This factory style method is speciffically used by a container to supply
          * an implementation of the abstract accessors in EJB2.0, but could be
          * usefull in other situations. This method should ALWAYS be used instead
          * of getBeanClass().newInstance();
          *
          * @return the new instance
          *
          * @see java.lang.Class#newInstance
          */
          public Object createBeanClassInstance() throws Exception {
          return getBeanClass().newInstance();
          }
          public Class getBeanClass()
          {
          return beanClass;
          }

          注意EntityContainer overwrite了這個方法:
          /**
          * Returns a new instance of the bean class or a subclass of the bean class.
          * If this is 1.x cmp, simply return a new instance of the bean class.
          * If this is 2.x cmp, return a subclass that provides an implementation
          * of the abstract accessors.
          *
          * @see java.lang.Class#newInstance
          *
          * @return The new instance.
          */
          public Object createBeanClassInstance() throws Exception {
          return persistenceManager.createBeanClassInstance();
          }
          其中 persistenceManager聲明為:
          /** This is the persistence manager for this container */
          protected EntityPersistenceManager persistenceManager;
          //persitenceManager和PersistenceStore我們將在第3部分講解。
          現在先給個大略印象:
          BMPPersistenceManager實現
          public Object createBeanClassInstance() throws Exception {
          return con.getBeanClass().newInstance();
          }

          CMPPersistenceManager實現
          EntityPersistenceStore store;
          public Object createBeanClassInstance() throws Exception
          {
          return store.createBeanClassInstance();
          }
          -------------------------------------------------------------------
          ok,接下來看看Container如何處理Client過來的Invocation。
          一切精彩盡在下面這個函數
          public Object invoke(Invocation mi);
          //Invocation代表了Client端過來的調用
          //Invocation里頭有些成員變量,指明了要調用的Method,
          //args,Transaction信息,principle/credential等信息。

          /** Maps for MarshalledInvocation mapping */
          protected Map marshalledInvocationMapping = new HashMap();

          public Object invoke(Invocation mi)
          throws Exception
          {
          Thread currentThread = Thread.currentThread();
          ClassLoader callerClassLoader = currentThread.getContextClassLoader();
          //保存原來的classloader,在finally里恢復

          Method m = null;
          Object type = null;

          try
          {
          currentThread.setContextClassLoader(this.classLoader);(注3)
          // Check against home, remote, localHome, local, getHome,
          // getRemote, getLocalHome, getLocal
          type = mi.getType();

          if(type == InvocationType.REMOTE ||
          type == InvocationType.LOCAL)
          {
          if (mi instanceof MarshalledInvocation)
          {
          ((MarshalledInvocation) mi).setMethodMap(
          marshalledInvocationMapping);
          }
          return internalInvoke(mi);
          }
          else if(type == InvocationType.HOME ||
          type == InvocationType.LOCALHOME)
          {
          if (mi instanceof MarshalledInvocation)
          {
          ((MarshalledInvocation) mi).setMethodMap(
          marshalledInvocationMapping);
          return internalInvokeHome(mi);
          }
          else
          {
          throw new MBeanException(new IllegalArgumentException(
          \\\\\\\"Unknown invocation type: \\\\\\\" + type));
          }
          }
          finally
          {
          currentThread.setContextClassLoader(callerClassLoader);
          }
          }

          ----------------------------------------------------------------
          MarshalledInvocation是Invocation的字類,代表可以從
          Client傳到Server的Invocation
          public class Invocation...

          public class MarshalledInvocation
          extends Invocation
          implements java.io.Externalizable
          而Invocation是在server端的調用鏈(Interceptor鏈,注4)
          間傳遞.
          -------------------------------------------------------
          ok,稍喘口氣,接下來看看兩個Internal的invoke,
          都是abstract,在字類實現
          public abstract Object internalInvokeHome(Invocation mi)
          throws Exception;
          public abstract Object internalInvoke(Invocation mi)
          throws Exception;
          至于具體實現么,TO BE CONITUE拉:)
          ----------------------------------------------------
          注1:ContainerPlugin可以放在容器里頭的東東。
          接口為interface ContainerPlugin :
          void setContainer(Container con);
          有InstancePool,InstanceCache,EJBProxyFactory/LocalProxyFactory,
          EntityPersistenceManager/EntityPersistenceStore等Plugin
          注2:metadata描述部署的信息,比如ejb-jar.xml,描述什么東東是
          entitybean,什么東東是sessionbean,session的是BMP/CMP等等。
          注3: Container的成員變量protected ClassLoader classLoader;
          用來load 這個Container里頭的類和資源,之所以要專門設一個Container
          的classLoader是因為能使EJB re-deployable.(JBoss定期掃描deploy目錄,
          如果ejb更改就進行redeploy,如果ejb刪除就undeploy)
          注4: Jboss會建立一個Interceptor 鏈,Invocation經過鏈傳遞。
          比如有EntityInterceptor,SecurityInterceptor,TransactionInterceptor,
          InvokerInterceptor,一個套一個,每個Interceptor對當前Invocation進行一些處理
          ,比如檢查權限,事物等等,然后傳給下一個Interceptor處理(這是Filter and Pipe模式了,也算是AOP拉~,別人說
          JBoss 這個Interceptor實現屬于AOP方言特別重:)。
          所有的Interceptor都是現
          Object invokeHome(Invocation mi) throws Exception;
          和Object invoke(Invocation mi) throws Exception;
          在自己invoke的最后,
          經過所有的Interceptor之后,調用下一個。
          看看AbstractInterceptor的缺省實現:
          public abstract class AbstractInterceptor
          implements Interceptor

          public Object invokeHome(final Invocation mi) throws Exception {
          //do sth.
          return getNext().invokeHome(mi);
          }
          public Object invoke(final Invocation mi) throws Exception {
          //do sth.
          return getNext().invoke(mi);
          }
          在經過重重Interceptor之后
          最后到達EJB Instance 調用你要的那個方法。
          其實實現很簡單:
          public Object internalInvokeHome(Invocation mi) throws Exception
          {
          return getInterceptor().invokeHome(mi);
          }

          public Object internalInvoke(Invocation mi) throws Exception
          {
          // Invoke through interceptors
          return getInterceptor().invoke(mi);
          }

          public Interceptor getInterceptor()
          {
          return interceptor;
          }
          protected Interceptor interceptor;
          //這是Container建立的Interceptor鏈的頭一個,從這里調起~
          再來看看 void addInterceptor(Interceptor in);這個函數
          在Interceptor鏈最后再掛一個Interceptor
          public void addInterceptor(Interceptor in)
          {
          if (interceptor == null)
          {
          interceptor = in;
          }
          else
          {
          Interceptor current = interceptor;
          while (current.getNext() != null)
          {
          current = current.getNext();
          }

          current.setNext(in);
          }
          }
          ------------------------------------------------------------------------
          附帶再提一下pool和cache
          /** This is the instance cache for this container */
          protected InstanceCache instanceCache;

          /** This is the instancepool that is to be used */
          protected InstancePool instancePool;
          /** This is the instancepool that is to be used */
          protected InstancePool instancePool;
          -------------------------------------------------------------
          public void setInstanceCache(InstanceCache ic)
          {
          if (ic == null)
          throw new IllegalArgumentException(\\\"Null cache\\\");

          this.instanceCache = ic;
          ic.setContainer(this);
          }

          public InstanceCache getInstanceCache()
          {
          return instanceCache;
          }
          public void setInstancePool(InstancePool ip)
          {
          if (ip == null)
          throw new IllegalArgumentException(\\\"Null pool\\\");

          this.instancePool = ip;
          ip.setContainer(this);
          }
          -----------------------------------------------------------------------
          ok,現在讓我們來看看Container都對EJB Instance暴露出來的
          方法都作了些什么,還有如何調用EJB Instance的方法.
          這里有重要的2個Map
          /**
          * These are the mappings between the home interface methods and the
          * container methods.
          * 所有Home 方法映射都存這里
          */
          protected Map homeMapping = new HashMap();

          /**
          * These are the mappings between the remote/local interface methods and the
          * bean methods.
          * 所有EJBObject方法映射都存這里
          */
          protected Map beanMapping = new HashMap();
          --------------------------------------------------------------------------
          class ContainerInterceptor
          extends AbstractContainerInterceptor
          //AbstractContainerInterceptor基本上什么都不做,不用看
          //ContainerInterceptor代表Container setup的Interceptor調用
          //鏈的最后一個,到這里你就會看到他調用了你的EJB Instance的方法
          {
          public Object invokeHome(Invocation mi) throws Exception
          {
          // Invoke and handle exceptions
          Method miMethod = mi.getMethod();
          Method m = (Method) homeMapping.get(miMethod);
          if (m.getDeclaringClass().equals(EntityContainer.class))
          {
          try
          {
          return m.invoke(EntityContainer.this, new Object[] { mi });
          }
          catch (Exception e)
          {
          rethrow(e);
          }
          }
          else // Home method
          {
          try
          {
          return m.invoke(((EnterpriseContext) mi.getEnterpriseContext()).getInstance(), mi.getArguments());
          }
          catch (Exception e)
          {
          rethrow(e);
          }
          }

          // We will never get this far, but the compiler does not know that
          throw new org.jboss.util.UnreachableStatementException();
          }

          public Object invoke(Invocation mi) throws Exception
          {
          // Get method
          Method miMethod = mi.getMethod();
          Method m = (Method) beanMapping.get(miMethod);
          if( m == null )
          {
          String msg = \\\"Invalid invocation, check your deployment packaging\\\"
          +\\\", method=\\\"+miMethod;
          throw new EJBException(msg);
          }

          // Select instance to invoke (container or bean)
          if (m.getDeclaringClass().equals(EntityContainer.class))
          {
          // Invoke and handle exceptions
          try
          {
          return m.invoke(EntityContainer.this, new Object[]{ mi });
          }
          catch (Exception e)
          {
          rethrow(e);
          }
          }
          else
          {
          // Invoke and handle exceptions
          try
          {
          return m.invoke(((EnterpriseContext) mi.getEnterpriseContext()).getInstance(), mi.getArguments());
          }
          catch (Exception e)
          {
          rethrow(e);
          }
          }

          // We will never get this far, but the compiler does not know that
          throw new org.jboss.util.UnreachableStatementException();
          }
          }

          //可以看到,兩個Map作了個映射,Map的Key為
          在你想要調用的EJB instance方法,value為實際
          實現的方法,可能就是EJB instance本身實現的方法,
          或者是容器幫忙實現的(比如CMP 中abstract get/set方法,
          只能容器幫忙實現).
          從這里也可以看出來,JBoss主要是保存了方法映射來處理
          EJBObject/EJBLocalObject 的調用請求,
          而其他一些J2EE AS是通過動態生成EJBObject/EJBLocalObject
          和你的EJB Instance的字類來實現的(而JBoss就算在CMP2.0
          里動態生成了一個東東,那也不是EJB Instance的子類)。
           
          ok,基本弄明白了Container的原理之后,我們來看看
          到底Container的一些初始化操作
          Container算是一項服務,
          JBoss在deploy/undeploy/redeploy時會調用
          與Service相關的幾個函數:
          protected void createService() throws Exception {}
          protected void startService() throws Exception {}
          protected void stopService() throws Exception {}
          protected void destroyService() throws Exception {}
          讓我們從EntityContainer看起:

          protected void createService() throws Exception
          {
          // Associate thread with classloader
          ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
          Thread.currentThread().setContextClassLoader(getClassLoader());

          try
          {
          // Acquire classes from CL
          //從metadata拿到Home/Remote的Class
          if (metaData.getHome() != null)
          homeInterface = classLoader.loadClass(metaData.getHome());
          if (metaData.getRemote() != null)
          remoteInterface = classLoader.loadClass(metaData.getRemote());

          // Call default init
          // 調用Container里頭的CreateService,我們回頭再看
          super.createService();

          //建立剛才所說的兩個Method映射Map
          setupBeanMapping();
          setupHomeMapping();

          // Map the interfaces to Long
          setupMarshalledInvocationMapping();

          // Initialize pool
          instancePool.create();
          // Try to register the instance pool as an MBean
          try
          {
          ObjectName containerName = super.getJmxName();
          Hashtable props = containerName.getKeyPropertyList();
          props.put(\\\"plugin\\\", \\\"pool\\\");
          ObjectName poolName = new ObjectName(containerName.getDomain(), props);
          server.registerMBean(instancePool, poolName);
          }
          catch(Throwable t)
          {
          log.debug(\\\"Failed to register cache as mbean\\\", t);
          }

          // Init instance cache
          instanceCache.create();
          // Try to register the instance cache as an MBean
          try
          {
          ObjectName containerName = super.getJmxName();
          Hashtable props = containerName.getKeyPropertyList();
          props.put(\\\"plugin\\\", \\\"cache\\\");
          ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
          server.registerMBean(instanceCache, cacheName);
          }
          catch(Throwable t)
          {
          log.debug(\\\"Failed to register cache as mbean\\\", t);
          }


          for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
          {
          String invokerBinding = (String)it.next();
          EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
          ci.create();
          }



          // Init persistence
          persistenceManager.create();

          // Initialize the interceptor by calling the chain
          Interceptor in = interceptor;
          while (in != null)
          {
          in.setContainer(this);
          in.create();
          in = in.getNext();
          }
          readOnly = ((EntityMetaData)metaData).isReadOnly();
          }
          finally
          {
          // Reset classloader
          Thread.currentThread().setContextClassLoader(oldCl);
          }
          }



          protected void startService() throws Exception
          {
          // Associate thread with classloader
          ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
          Thread.currentThread().setContextClassLoader(getClassLoader());

          try
          {
          // Call default start
          super.startService();

          // Start container invokers
          for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
          {
          String invokerBinding = (String)it.next();
          EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
          ci.start();
          }

          // Start instance cache
          instanceCache.start();

          // Start persistence
          persistenceManager.start();

          // Start the instance pool
          instancePool.start();

          // Start all interceptors in the chain
          Interceptor in = interceptor;
          while (in != null)
          {
          in.start();
          in = in.getNext();
          }
          }
          finally
          {
          // Reset classloader
          Thread.currentThread().setContextClassLoader(oldCl);
          }
          }

          protected void stopService() throws Exception
          {
          // Associate thread with classloader
          ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
          Thread.currentThread().setContextClassLoader(getClassLoader());

          try
          {
          //Stop items in reverse order from start
          //This assures that CachedConnectionInterceptor will get removed
          //from in between this and the pm before the pm is stopped.
          // Stop all interceptors in the chain
          Interceptor in = interceptor;
          while (in != null)
          {
          in.stop();
          in = in.getNext();
          }

          // Stop the instance pool
          instancePool.stop();


          // Stop persistence
          persistenceManager.stop();

          // Stop instance cache
          instanceCache.stop();

          // Stop container invoker
          for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
          {
          String invokerBinding = (String)it.next();
          EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
          ci.stop();
          }

          // Call default stop
          super.stopService();
          }
          finally
          {
          // Reset classloader
          Thread.currentThread().setContextClassLoader(oldCl);
          }
          }

          protected void destroyService() throws Exception
          {
          // Associate thread with classloader
          ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
          Thread.currentThread().setContextClassLoader(getClassLoader());

          try
          {
          // Destroy container invoker
          for (Iterator it = proxyFactories.keySet().iterator(); it.hasNext(); )
          {
          String invokerBinding = (String)it.next();
          EJBProxyFactory ci = (EJBProxyFactory)proxyFactories.get(invokerBinding);
          ci.destroy();
          }

          // Destroy instance cache
          instanceCache.destroy();
          instanceCache.setContainer(null);
          try
          {
          ObjectName containerName = super.getJmxName();
          Hashtable props = containerName.getKeyPropertyList();
          props.put(\\\"plugin\\\", \\\"cache\\\");
          ObjectName cacheName = new ObjectName(containerName.getDomain(), props);
          server.unregisterMBean(cacheName);
          }
          catch(Throwable ignore)
          {
          }

          // Destroy persistence
          persistenceManager.destroy();
          persistenceManager.setContainer(null);

          // Destroy the pool
          instancePool.destroy();
          instancePool.setContainer(null);
          try
          {
          ObjectName containerName = super.getJmxName();
          Hashtable props = containerName.getKeyPropertyList();
          props.put(\\\"plugin\\\", \\\"pool\\\");
          ObjectName poolName = new ObjectName(containerName.getDomain(), props);
          server.unregisterMBean(poolName);
          }
          catch(Throwable ignore)
          {
          }

          // Destroy all the interceptors in the chain
          Interceptor in = interceptor;
          while (in != null)
          {
          in.destroy();
          in.setContainer(null);
          in = in.getNext();
          }

          MarshalledInvocation.removeHashes(homeInterface);
          MarshalledInvocation.removeHashes(remoteInterface);

          // Call default destroy
          super.destroyService();
          }
          finally
          {
          // Reset classloader
          Thread.currentThread().setContextClassLoader(oldCl);
          }
          }
          ------------------------------------------------------------
          protected void setupBeanMapping() throws Exception
          {
          try {
          if (remoteInterface != null)
          {
          Method[] m = remoteInterface.getMethods();
          setupBeanMappingImpl( m, \\\"javax.ejb.EJBObject\\\" );
          }
          if (localInterface != null)
          {
          Method[] m = localInterface.getMethods();
          setupBeanMappingImpl( m, \\\"javax.ejb.EJBLocalObject\\\" );
          }
          }
          catch (Exception e)
          {
          // ditch the half built mappings
          homeMapping.clear();
          beanMapping.clear();

          throw e;
          }
          }

          private void setupBeanMappingImpl( Method[] m, String intfName )
          throws Exception
          {
          for (int i = 0; i < m.length; i++)
          {
          if (!m.getDeclaringClass().getName().equals(intfName))
          {
          // Implemented by bean
          beanMapping.put(m, beanClass.getMethod(m.getName(), m.getParameterTypes()));
          }
          else
          {
          // Implemented by container
          beanMapping.put(m, getClass().getMethod(m.getName(),
          new Class[] { Invocation.class }));
          }
          }
          }
          private void setupHomeMappingImpl(Method[] m,
          String finderName,
          String append)
          throws Exception
          {
          // Adrian Brock: This should go away when we don\\\'t support EJB1x
          boolean isEJB1x = metaData.getApplicationMetaData().isEJB1x();

          for (int i = 0; i < m.length; i++)
          {
          String methodName = m.getName();
          try
          {
          try // Try home method
          {
          String ejbHomeMethodName = \\\"ejbHome\\\" + methodName.substring(0,1).toUpperCase() + methodName.substring(1);
          homeMapping.put(m, beanClass.getMethod(ejbHomeMethodName, m.getParameterTypes()));

          continue;
          }
          catch (NoSuchMethodException ignore) {} // just go on with other types of methods


          // Implemented by container (in both cases)
          if (methodName.startsWith(\\\"find\\\"))
          {
          homeMapping.put(m, this.getClass().getMethod(finderName, new Class[] { Invocation.class }));
          }
          else if (methodName.equals(\\\"create\\\") ||
          (isEJB1x == false && methodName.startsWith(\\\"create\\\")))
          {
          homeMapping.put(m, this.getClass().getMethod(\\\"create\\\"+append, new Class[] { Invocation.class }));
          beanMapping.put(m, this.getClass().getMethod(\\\"postCreate\\\"+append, new Class[] { Invocation.class }));
          }
          else
          {
          homeMapping.put(m, this.getClass().getMethod(methodName+append, new Class[] { Invocation.class }));
          }
          }
          catch (NoSuchMethodException e)
          {
          throw new NoSuchMethodException(\\\"Could not find matching method for \\\"+m);
          }
          }
          }

          protected void setupHomeMapping() throws Exception
          {
          try {
          if (homeInterface != null)
          {
          Method[] m = homeInterface.getMethods();
          setupHomeMappingImpl( m, \\\"find\\\", \\\"Home\\\" );
          }
          if (localHomeInterface != null)
          {
          Method[] m = localHomeInterface.getMethods();
          setupHomeMappingImpl( m, \\\"findLocal\\\", \\\"LocalHome\\\" );
          }

          // Special methods

          // Get the One on Handle (getEJBObject), get the class
          Class handleClass = Class.forName(\\\"javax.ejb.Handle\\\");

          // Get the methods (there is only one)
          Method[] handleMethods = handleClass.getMethods();

          //Just to make sure let\\\'s iterate
          for (int j=0; j {
          //Get only the one called handle.getEJBObject
          if (handleMethods[j].getName().equals(\\\"getEJBObject\\\"))
          {
          //Map it in the home stuff
          homeMapping.put(handleMethods[j],
          this.getClass().getMethod(\\\"getEJBObject\\\",
          new Class[] {Invocation.class}));
          }
          }
          }
          catch (Exception e)
          {
          // ditch the half built mappings
          homeMapping.clear();
          beanMapping.clear();

          throw e;
          }
          }

          posted on 2005-03-29 09:46 笨笨 閱讀(688) 評論(0)  編輯  收藏 所屬分類: J2EE 、ALLJBOSS
          主站蜘蛛池模板: 庆云县| 仲巴县| 罗平县| 宜城市| 肃北| 峨边| 墨脱县| 闸北区| 右玉县| 仪陇县| 德化县| 尼木县| 土默特左旗| 阳泉市| 衢州市| 镇平县| 镇江市| 法库县| 嘉鱼县| 双峰县| 红河县| 那曲县| 泸溪县| 东阳市| 山东| 崇信县| 湟中县| 漠河县| 玛多县| 闽清县| 进贤县| 拉萨市| 松潘县| 台东市| 青海省| 永康市| 庄浪县| 固阳县| 凤台县| 桐梓县| 共和县|