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()
发表评论