jboss连接池的启动,主要就是一些对象的初始化及一个prefill的过程。
prefill参数:在ds.xml中有一个参数,叫prefill,这个值可以设置为true|false,默认为false,这个参数在JBOSS4.0.5版本以上才能被支持。这个参数的设置,决定了连接池在启动时是否会初始化min连接数(最小连接数)。如果设置为true,连接池在启动的时候会进行min值连接数的初始化,但是在应用同时启动时可能导致连接风暴;如果设置为false,则在第一次getconnection时,才启动创建min连接数。
本节主要研究了JBOSS连接池在启动时究竟做了些什么操作,带着好奇心,我们查看JBOSS源码,其实并不难,可以看到在连接池的启动过程中主要涉及到两个类,InternalManagedConnectionPool和PoolFiller。
PoolFiller类:在jboss启动时即开始fillerThread线程的wait,当执行fillPool操作时被唤醒,fillPool操作主要的作用是将JBOSS的连接池填充到min值。当连接池填充到min值之后,线程继续wait。
InternalManagedConnectionPool:这个类是JOBSS连接池管理的核心类,后面几节主要围绕这个类来展开。
InternalManagedConnectionPool类的构造方法和连接池的配置参数紧密相关,如下:
protected InternalManagedConnectionPool(ManagedConnectionFactory mcf,
ConnectionListenerFactory clf,
Subject subject, ConnectionRequestInfo cri,
PoolParams poolParams, Logger log)
{
//mcf是连接管工厂
this.mcf = mcf;
//连接监听工厂
this.clf = clf;
//默认的subject
defaultSubject = subject;
//连接请求信息
defaultCri = cri;
//连接池参数,主要方法见下面的函数,见附录。
this.poolParams = poolParams;
this.maxSize = this.poolParams.maxSize;
this.log = log;
this.trace = log.isTraceEnabled();
//可以使用的连接事件监听器初始化。
cls = new ArrayList(this.maxSize);
/*创建一个对应连接事件监听器的信号集,用于连接的获取。
每次获取连接或者创建连接之前,都需要获取信号量,
当没有可用的信号量时,表示连接已经到达max值。
*/
permits = new FIFOSemaphore(this.maxSize);
/*
判断jboss配置文件中的prefill设置,默认为false。
如果设置为true,则将本连接池加入到一个临时pool(LinkedList)的最后,
加入的方式是串行的(线程安全)。
*/
if(poolParams.prefill)
{
//fillPool主要执行了一个fillToMin的方法,即将连接池中的连接,填充到min值。
PoolFiller.fillPool(this);
}
}
这就是InternalManagedConnectionPool的实例化,很简单,最后一步判断如果参数prefill设置为flase,则没有其它事了,整个过程结束。否则,执行一个fillPool的操作。
先来看一下与PoolFiller类,PoolFiller在构造函数中即完成fillerThread线程的启动,线程启动后由于pools是空的,所以本线程一直处于wait状态,当执行PoolFiller.fillPool(this); 操作时,pools中首先会增加了一个连接池对象(见internalFillPool函数),然后幻醒fillerThread线程,fillerThread线程被唤醒后,因为此时pools已经不为null了,线程开始初始化pools队列中的所有的连接池对象(在并发情况下,可能有多个连接池对象需要初始化,但是连接初始化的过程,是一个线程安全的操作),线程唤醒后主要的操作是将连接池的连接数填充至min值,填充由fillToMin函数来执行。
当pools中所有的连接池对象都填充到min值时,此时pools也被清空了,fillerThread线程继续进行wait,直到下一次fillPool时被唤醒。在连接池启动时只会被fillPool一次,其它的fillPool操作还会在三种情况下发生:
1.后面的章节会讲到在removeTimedOut(idle超时清理时,还会调会fillPool操作-即清理Idle连接后,发现小于min值,又需要进行fillPool操作)。
2.在valitionconnection后,紧接着执行fillToMin。(同上)
3.当prefill设置为false,即连接池实例化时没有被fill到min值,在第一次getconnection时,触发这个fillPool操作。
具体如下图所示:

public class PoolFiller implements Runnable
{
private final LinkedList pools = new LinkedList();
private final Thread fillerThread;
private static final PoolFiller filler = new PoolFiller();
public static void fillPool(InternalManagedConnectionPool mcp)
{
filler.internalFillPool(mcp);
}
public PoolFiller ()
{
fillerThread = new Thread(this, "JCA PoolFiller");
fillerThread.start();
}
public void run()
{
ClassLoader myClassLoader = getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(myClassLoader);
//keep going unless interrupted
while (true)
{
try
{
InternalManagedConnectionPool mcp = null;
//keep iterating through pools till empty, exception escapes.
while (true)
{
synchronized (pools)
{
//取出需要处理的连接池,即需要fillToMin的连接池
mcp = (InternalManagedConnectionPool)pools.removeFirst();
}
//如果没有需要处理的连接池了,则跳出while循环,进行线程的wait。
if (mcp == null)
break;
//将连接池mcp填充至min值。
mcp.fillToMin();
}
}
catch (Exception e)
{
}
try
{
synchronized (pools)
{
/*如果没有需要处理的连接池了,则跳出while循环,
进行线程的wait,等待下一次执行internalFillPool函数唤醒filltoMin
*/
while(pools.isEmpty())
{
pools.wait();
}
}
}
catch (InterruptedException ie)
{
return;
}
}
}
private void internalFillPool(InternalManagedConnectionPool mcp)
{
synchronized (pools)
{
/*
将连接池对象加入到pools临时队列里,
这里的pools只是一个临时队列,用于进行fillToMin的操作。
*/
pools.addLast(mcp);
//notify()会触发器run
pools.notify();
}
}
}
fillToMin函数如下:
public void fillToMin()
{
while (true)
{
/*
获取一个信号量 - 防止在连接池快满时,产生竞争
当所有的连接都被checkd out(即全部被占用)时,避免不需要的fill检查。
*/
try
{
//获取信号量,超时时间为jboss数据源配置文件的time out
if (permits.attempt(poolParams.blockingTimeout))
{
try
{
//判断连接池是否已经shutdown?如果已经shutdown,则直接返回。
if (shutdown.get())
return;
// 判断连接池中的连接是否已经达到min值,如果已经达到,则直接返回。
if (getMinSize() - connectionCounter.getGuaranteedCount()
发表评论