對于啟用、禁止或修改特定連接或其組件的功能而言,使用攔截器無疑是一種非常強(qiáng)大的方式。There are many different use cases for when interceptors are useful。默認(rèn)情況下,基于性能方面的考慮,連接池是無狀態(tài)的。連接池本身所插入的狀態(tài)是 defaultAutoCommit、defaultReadOnly、defaultTransactionIsolation,或 defaultCatalog(如果設(shè)置了這些狀態(tài))。這 4 個狀態(tài)只有在連接創(chuàng)建時才設(shè)置。無論這些屬性是否在連接使用期間被修改,池本身都不能重置它們。
攔截器必須擴(kuò)展自 org.apache.tomcat.jdbc.pool.JdbcInterceptor 類。該類相當(dāng)簡單,你必須利用一個無參數(shù)構(gòu)造函數(shù)。
public JdbcInterceptor() {
}
當(dāng)從連接池借出一個連接時,攔截器能夠通過實現(xiàn)以下方法,初始化這一事件或以一些其他形式來響應(yīng)該事件。
public abstract void reset(ConnectionPool parent, PooledConnection con);
上面這個方法有兩個參數(shù),一個是連接池本身的引用 ConnectionPool parent,一個是底層連接的引用 PooledConnection con。
當(dāng)調(diào)用 java.sql.Connection 對象上的方法時,會導(dǎo)致以下方法被調(diào)用:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Method method 是被調(diào)用的實際方法,Object[] args 是參數(shù)。通過觀察下面這個非常簡單的例子,我們可以解釋如果當(dāng)連接已經(jīng)關(guān)閉時,如何讓 java.sql.Connection.close() 的調(diào)用變得無用。
if (CLOSE_VAL==method.getName()) {
if (isClosed()) return null; //noop for already closed.
}
return super.invoke(proxy,method,args);
當(dāng)連接池開啟或關(guān)閉時,你可以得到相關(guān)通知。可能每個攔截器類只通知一次,即使它是一個實例方法。也可能使用當(dāng)前未連接到池中的攔截器來通知你。
public void poolStarted(ConnectionPool pool) {
}
public void poolClosed(ConnectionPool pool) {
}
當(dāng)重寫這些方法時,如果你擴(kuò)展自 JdbcInterceptor 之外的類,不要忘記調(diào)用超類。
攔截器可以通過 jdbcInterceptors 屬性或 setJdbcInterceptors 方法來配置。攔截器也可以有屬性,可以通過如下方式來配置:
String jdbcInterceptors=
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState(useEquals=true,fast=yes)"
既然攔截器也有屬性,那么你也可以讀取其中的屬性值。你可以重寫 setProperties 方法。
public void setProperties(Map properties) {
super.setProperties(properties);
final String myprop = "myprop";
InterceptorProperty p1 = properties.get(myprop);
if (p1!=null) {
setMyprop(Long.parseLong(p1.getValue()));
}
}
連接池圍繞實際的連接創(chuàng)建包裝器,為的是能夠正確地池化。同樣,為了執(zhí)行特定的功能,我們也可以在這些包裝器中創(chuàng)建攔截器。如果不需要獲取實際的連接,可以使用 javax.sql.PooledConnection 接口。
Connection con = datasource.getConnection();
Connection actual = ((javax.sql.PooledConnection)con).getConnection();
下面利用 1.6 來構(gòu)建 JDBC 連接池代碼,但它也可以向后兼容到 1.5 運行時環(huán)境。為了單元測試,使用 1.6 或更高版本。
更多的關(guān)于 JDBC 用途的 Tomcat 配置范例可參看 [Tomcat 文檔]()。
構(gòu)建非常簡單。池依賴于 tomcat-juli.jar,在這種情況下,需要 SlowQueryReportJmx。
javac -classpath tomcat-juli.jar \
-d . \
org/apache/tomcat/jdbc/pool/*.java \
org/apache/tomcat/jdbc/pool/interceptor/*.java \
org/apache/tomcat/jdbc/pool/jmx/*.java
構(gòu)建文件位于 Tomcat 的源代碼倉庫中。
為了方便起見,在通過簡單構(gòu)建命令生成所需文件的地方也包含了一個構(gòu)建文件。
ant download (downloads dependencies)
ant build (compiles and generates .jar files)
ant dist (creates a release package)
ant test (runs tests, expects a test database to be setup)
系統(tǒng)針對 Maven 構(gòu)建進(jìn)行組織,但是沒有生成發(fā)布組件,只有庫本身。