http://blog.csdn.net/stripbolt/archive/2004/10/24/149705.aspxJBoss是一個(gè)非常優(yōu)秀的J2EE的Application Server,研究
它的源代碼有助于我們更好的理解J2EE的各種技術(shù)。
本系列擬從四個(gè)方面分析Jboss源碼:
1.EJB Container實(shí)現(xiàn)
2.Transaction實(shí)現(xiàn)
3.Persistence Mapping
4.Client到Server端的Invocation
-------------------------------------------------------------------
先說(shuō)第1點(diǎn):EJB Container實(shí)現(xiàn)。
1.1 EJB Pool
我們知道,EJB Container 會(huì)維護(hù)一個(gè)EJB池,
在多個(gè)client間共享,避免頻繁創(chuàng)建銷毀對(duì)象的開銷。
讓我們來(lái)看看Jboss實(shí)現(xiàn)的Pool:
EJB分EntityBean,MDB,Stateless/Stateful Session Bean,
而Jboss中也對(duì)應(yīng)的有EntityInstancePool,MessageDrivenInstancePool,
StatefulSessionInstancePool,StatelessSessionInstancePool.
讓我們先從這4個(gè)類的共同基類AbstractInstancePool看起:
class AbstractInstancePool實(shí)現(xiàn)了接口InstancePool,該接口有以下幾個(gè)方法:
EnterpriseContext get() throws Exception;
void free(EnterpriseContext ctx);
void discard(EnterpriseContext ctx);
int getCurrentSize();
public int getMaxSize();
--------------------------------------------------------------------
先對(duì)EnterpriseContext作番說(shuō)明。EnterpriseContext的作用
就是把具體的EJB instance和它的metadata聯(lián)系起來(lái)。
該類簽名為:
public abstract class EnterpriseContext,
有4個(gè)子類,EntityEnterpriseContext,MessageDrivenEnterpriseContext,
StatefulSessionEnterpriseContext,StatelessSessionEnterpriseContext。
分別對(duì)應(yīng)4種類型的EJB。
EnterpriseContext中有幾個(gè)重要的成員變量。
/** The EJB instance */
Object instance;
/** The container using this context */
Container con; //Container這個(gè)類是JBoss用來(lái)代表對(duì)EJB提供Transaction,Security,Pool等服務(wù)的類,我們回頭還會(huì)再說(shuō)。
/** Only StatelessSession beans have no Id, stateful and entity do */
Object id;
/** The transaction associated with the instance */
Transaction transaction; //Transaction,我們下節(jié)再說(shuō).
// 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(); //由子類實(shí)現(xiàn)
//返回javax.ejb.EJBContext,注意這個(gè)EJBContext是
EJB規(guī)范要求提供給EJB的Context,與JBoss自己實(shí)現(xiàn)類EnterpriseContext沒(méi)有關(guān)系。
/** 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這個(gè)成員變量表示當(dāng)前這個(gè)EJB instance有沒(méi)人在用。
//這個(gè)變量用來(lái)給Reentrance,以及canPassviate用.
/**
* before reusing this context we clear it of previous state called
* by pool.free()
* 從pool里取出來(lái)的時(shí)候沒(méi)有關(guān)聯(lián)任何EJB instance和Transaction信息
* 在返還pool的時(shí)候把這些信息清掉。
*/
public void clear() {
this.id = null;
this.locked = 0;
this.transaction = null;
}
//-------------------------------------------------------------------------------------
protected boolean isContainerManagedTx()
{
BeanMetaData md = (BeanMetaData)con.getBeanMetaData();
return md.isContainerManagedTx();
}
//從關(guān)聯(lián)的container拿出對(duì)應(yīng)的metadata,判斷是否CMT.
//注意這里con是Container成員變量,可不是什么連接,連接一般縮寫為conn,
//我一開始就搞混了:)
//BeanMetaData這些MetaData的子類都是從xml配置里頭讀出來(lái)的Metadata構(gòu)造的,
//沒(méi)什么神秘的.
這個(gè)類里頭還有兩個(gè)inner class,EJBContextImpl implements EJBContext,
UserTransactionImpl implements UserTransaction。EJBContextImpl等
講解過(guò)Container再說(shuō),UserTransaction等下節(jié)再說(shuō)。
現(xiàn)在讓我們來(lái)看看EnterpriseContext的幾個(gè)子類:
首先類比一下幾個(gè)子類的成員變量:
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;
看來(lái)除了MDB沒(méi)有對(duì)應(yīng)的EJBObject/EJBLocalObject,其他統(tǒng)統(tǒng)都有:)
學(xué)過(guò)EJB的人都知道,在語(yǔ)法上EJB instance 是implements
EntityBean/SessionBean/MessageDrivenBean (這3個(gè)interface有一個(gè)共同的
interface: public interface EnterpriseBean extends Serializable,
EnterpriseBean 是個(gè)Marker接口,里頭什么都沒(méi)有,好像Serializable接口一樣,只說(shuō)明
實(shí)現(xiàn)它的是個(gè)EJB.而EntityBean/SessionBean/MessageDrivenBean 有對(duì)應(yīng)的
void ejbActivate() throws EJBException, RemoteException;
void ejbLoad() throws EJBException, RemoteException;
一些方法需要實(shí)現(xiàn)。(雖然常常是空實(shí)現(xiàn):),由容器作了很多事)
至于EJBObject/EJBLocalObject 在語(yǔ)法上都是非直接實(shí)現(xiàn)的,代表EJB instance暴露出的Remote/Local 接口。既然這些EJB instance非直接實(shí)現(xiàn)這些接口,那么這些接口如何與具體的EJB instance相關(guān)聯(lián),我們講到Container類時(shí)就知道了。
----------------------------------------------------------------------------------
EnterpriseContext的子類EntityEnterpriseContext的構(gòu)造函數(shù)
public EntityEnterpriseContext(Object instance, Container con)
throws RemoteException
{
super(instance, con);
ctx = new EntityContextImpl(); //這是EJBContextImpl的子類,不急著說(shuō):)
((EntityBean)instance).setEntityContext(ctx);//看看,原來(lái)set...Context是在這里調(diào)用的//其它instance實(shí)現(xiàn)的什么ejbCreate(),EJBLoad,EJBActive()到底是什么時(shí)候
調(diào)用的呢?接下來(lái)我們慢慢找,這可散布在各地呢:)
}
//其他幾個(gè)子類的構(gòu)造函數(shù)前3行也都如此,是類似的。
對(duì)于StatelessSessionEnterpriseContext和MessageDrivenEnterpriseContext,緊接的是
Method ejbCreate = instance.getClass().getMethod(\"ejbCreate\", new Class[0]);
ejbCreate.invoke(instance, new Object[0]);
//看看,來(lái)了一個(gè)ejbCreate:),對(duì)于StatelessSessionBean,一上來(lái)就ejbCreate()了~
接下來(lái)看點(diǎn)簡(jiǎn)單的:對(duì)于EnterpriseContext,
有public abstract void discard() throws RemoteException;
對(duì)于MessageDriven...的
public void discard() throws RemoteException
{
((MessageDrivenBean)instance).ejbRemove();
}
對(duì)于StatelessSession的
public void discard() throws RemoteException
{
((SessionBean)instance).ejbRemove();
}
對(duì)于StatefulSession...的
public void discard() throws RemoteException
{
// Do nothing
}
對(duì)于Entity....
public void discard() throws RemoteException
{
((EntityBean)instance).unsetEntityContext();
}
//discard 是在AbstractInstancePool中的
void discard(EnterpriseContext ctx);調(diào)用的
/**
* 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還有個(gè)free方法:
public void free(EnterpriseContext ctx) {
ctx.clear();//記得ctx只是清掉id,transaction等,返回pool,準(zhǔn)備復(fù)用么?
//discard是在發(fā)生錯(cuò)誤的時(shí)候,不希望擴(kuò)大影響,于是discard掉,
//而對(duì)應(yīng)get()的free方法只是把EnterpriseContext返還給pool.
}
----------------------------------------------------------------------------------
專門對(duì)于Stateful....Context有設(shè)置EJB instance的函數(shù)
/**
* 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
多了個(gè)implements Serializable,(其他都沒(méi)有),
這是為了支持Activation/Passviation,Passviation的時(shí)候
把EJB Instance寫到文件中。
在StatefulSessionEnterpriseContext中有這樣兩個(gè)方法
private void writeObject(ObjectOutputStream out)
throws IOException, ClassNotFoundException
{
// do nothing
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
// do nothing
}
//說(shuō)明序列化的時(shí)候StatefulSessionEnterpriseContext本身不需要
寫出什么狀態(tài),只有對(duì)應(yīng)的EJB instance才需要寫出狀態(tài)。
現(xiàn)在來(lái)看AbstractInstancePool的源碼,由于內(nèi)容太多
就不詳細(xì)解釋了。
先看Abstract...Pool的create(Object instance)函數(shù)熱熱身~
Abstract...Pool
// Protected -----------------------------------------------------
protected abstract EnterpriseContext create(Object instance)
throws Exception;
對(duì)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;//對(duì)于MDB和StatelessSessionBean,這個(gè)變量被設(shè)為true,// for MDB, we *do* pool // for SLSB, we *do* pool
ok,現(xiàn)在來(lái)看pool的重頭戲,get()/free(EnterpriseContext ctx)函數(shù)
(discard(EnterpriseContext ctx)前面講過(guò),不再重復(fù))
這幾個(gè)函數(shù)也是Interface InstancePool里頭要實(shí)現(xiàn)的接口:)
閑話少說(shuō),來(lái)看代碼~~
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里頭有東東就拿出來(lái)
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;
}
}
}
對(duì)于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掉不用了~
}
剩下的下回再講,先預(yù)告2個(gè)類體系:
1.AbstractInstanceCache ,有EntityInstanceCache和StatefulSessionInstanceCache 子類。對(duì)于Entity,用它的
PrimaryKey作Cache的Key,對(duì)于Stateful,Jboss也會(huì)付給
每個(gè)instance一個(gè)唯一標(biāo)定的值用來(lái)做CacheKey.
Abstract...Cache與Abstract...Pool結(jié)合使用,得到好的Performance。
2.public abstract class Container,
有EntityContainer,MessageDrivenContainer,Stateful/StatelessSessionContainer
4個(gè)子類,用來(lái)提供對(duì)EJB instance的transaction/security/pool等服務(wù)。
//看看它的成員變量,就能猜個(gè)大概
/** 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,以前說(shuō)過(guò)Container有4種子類,分別對(duì)應(yīng)4種類型的EJB.
一個(gè)Container是所有Container plugins(注1)和metadata(注2)的集散地,the container plugins可以從container拿到metadata和其他container plugins.EJB部署的時(shí)候會(huì)創(chuàng)建相應(yīng)的Container.Container基本不做太多事,主要delegate給plugins作事情。
ok,讓我們來(lái)看看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作為一個(gè)單元部署的Module,比如一個(gè)ejb-jar就是一個(gè)Module,
/*這個(gè) ejb-jar里頭可能有多個(gè)entitybean,sessionbean,那么對(duì)于 每個(gè)entitybean,sessionbean
都會(huì)有一個(gè)對(duì)應(yīng)的container,而這些東東共享一個(gè)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了這個(gè)方法:
/**
* 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部分講解。
現(xiàn)在先給個(gè)大略印象:
BMPPersistenceManager實(shí)現(xiàn)
public Object createBeanClassInstance() throws Exception {
return con.getBeanClass().newInstance();
}
CMPPersistenceManager實(shí)現(xiàn)
EntityPersistenceStore store;
public Object createBeanClassInstance() throws Exception
{
return store.createBeanClassInstance();
}
-------------------------------------------------------------------
ok,接下來(lái)看看Container如何處理Client過(guò)來(lái)的Invocation。
一切精彩盡在下面這個(gè)函數(shù)
public Object invoke(Invocation mi);
//Invocation代表了Client端過(guò)來(lái)的調(diào)用
//Invocation里頭有些成員變量,指明了要調(diào)用的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();
//保存原來(lái)的classloader,在finally里恢復(fù)
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端的調(diào)用鏈(Interceptor鏈,注4)
間傳遞.
-------------------------------------------------------
ok,稍喘口氣,接下來(lái)看看兩個(gè)Internal的invoke,
都是abstract,在字類實(shí)現(xiàn)
public abstract Object internalInvokeHome(Invocation mi)
throws Exception;
public abstract Object internalInvoke(Invocation mi)
throws Exception;
至于具體實(shí)現(xiàn)么,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;
用來(lái)load 這個(gè)Container里頭的類和資源,之所以要專門設(shè)一個(gè)Container
的classLoader是因?yàn)槟苁笶JB re-deployable.(JBoss定期掃描deploy目錄,
如果ejb更改就進(jìn)行redeploy,如果ejb刪除就undeploy)
注4: Jboss會(huì)建立一個(gè)Interceptor 鏈,Invocation經(jīng)過(guò)鏈傳遞。
比如有EntityInterceptor,SecurityInterceptor,TransactionInterceptor,
InvokerInterceptor,一個(gè)套一個(gè),每個(gè)Interceptor對(duì)當(dāng)前Invocation進(jìn)行一些處理
,比如檢查權(quán)限,事物等等,然后傳給下一個(gè)Interceptor處理(這是Filter and Pipe模式了,也算是AOP拉~,別人說(shuō)
JBoss 這個(gè)Interceptor實(shí)現(xiàn)屬于AOP方言特別重:)。
所有的Interceptor都是現(xiàn)
Object invokeHome(Invocation mi) throws Exception;
和Object invoke(Invocation mi) throws Exception;
在自己invoke的最后,
經(jīng)過(guò)所有的Interceptor之后,調(diào)用下一個(gè)。
看看AbstractInterceptor的缺省實(shí)現(xiàn):
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);
}
在經(jīng)過(guò)重重Interceptor之后
最后到達(dá)EJB Instance 調(diào)用你要的那個(gè)方法。
其實(shí)實(shí)現(xiàn)很簡(jiǎn)單:
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鏈的頭一個(gè),從這里調(diào)起~
再來(lái)看看 void addInterceptor(Interceptor in);這個(gè)函數(shù)
在Interceptor鏈最后再掛一個(gè)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,現(xiàn)在讓我們來(lái)看看Container都對(duì)EJB Instance暴露出來(lái)的
方法都作了些什么,還有如何調(diào)用EJB Instance的方法.
這里有重要的2個(gè)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調(diào)用
//鏈的最后一個(gè),到這里你就會(huì)看到他調(diào)用了你的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();
}
}
//可以看到,兩個(gè)Map作了個(gè)映射,Map的Key為
在你想要調(diào)用的EJB instance方法,value為實(shí)際
實(shí)現(xiàn)的方法,可能就是EJB instance本身實(shí)現(xiàn)的方法,
或者是容器幫忙實(shí)現(xiàn)的(比如CMP 中abstract get/set方法,
只能容器幫忙實(shí)現(xiàn)).
從這里也可以看出來(lái),JBoss主要是保存了方法映射來(lái)處理
EJBObject/EJBLocalObject 的調(diào)用請(qǐng)求,
而其他一些J2EE AS是通過(guò)動(dòng)態(tài)生成EJBObject/EJBLocalObject
和你的EJB Instance的字類來(lái)實(shí)現(xiàn)的(而JBoss就算在CMP2.0
里動(dòng)態(tài)生成了一個(gè)東東,那也不是EJB Instance的子類)。
ok,基本弄明白了Container的原理之后,我們來(lái)看看
到底Container的一些初始化操作
Container算是一項(xiàng)服務(wù),
JBoss在deploy/undeploy/redeploy時(shí)會(huì)調(diào)用
與Service相關(guān)的幾個(gè)函數(shù):
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
// 調(diào)用Container里頭的CreateService,我們回頭再看
super.createService();
//建立剛才所說(shuō)的兩個(gè)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;
}
}