Replace ConnectionProxy’s ArrayList<Statement> with a custom class (FastStatementList), replace the singleton generated JavassistProxyFactory with a class that has static methods (so we get invokestatic rather than invokeinterface) in bytecode.

pull/30/head
Brett Wooldridge 11 years ago
parent 4a6eb29043
commit 04aa65a6d8

@ -29,6 +29,7 @@ import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.proxy.JavassistProxyFactory;
import com.zaxxer.hikari.util.PropertyBeanSetter;
public final class HikariConfig implements HikariConfigMBean
@ -64,6 +65,11 @@ public final class HikariConfig implements HikariConfigMBean
private Properties dataSourceProperties;
private DataSource dataSource;
static
{
JavassistProxyFactory.initialize();
}
/**
* Default constructor
*/

@ -32,7 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
import com.zaxxer.hikari.proxy.JavassistProxyFactoryFactory;
import com.zaxxer.hikari.proxy.ProxyFactory;
import com.zaxxer.hikari.util.PropertyBeanSetter;
/**
@ -325,7 +325,7 @@ public final class HikariPool implements HikariPoolMBean
try
{
Connection connection = dataSource.getConnection();
IHikariConnectionProxy proxyConnection = (IHikariConnectionProxy) JavassistProxyFactoryFactory.getProxyFactory().getProxyConnection(this, connection);
IHikariConnectionProxy proxyConnection = (IHikariConnectionProxy) ProxyFactory.getProxyConnection(this, connection);
if (transactionIsolation < 0)
{

@ -27,7 +27,7 @@ import java.util.Timer;
import java.util.TimerTask;
import com.zaxxer.hikari.HikariPool;
import com.zaxxer.hikari.util.FastList;
import com.zaxxer.hikari.util.FastStatementList;
/**
* This is the proxy class for java.sql.Connection.
@ -36,13 +36,11 @@ import com.zaxxer.hikari.util.FastList;
*/
public abstract class ConnectionProxy implements IHikariConnectionProxy
{
private static final ProxyFactory PROXY_FACTORY;
private static final Set<String> SQL_ERRORS;
protected final Connection delegate;
private final FastList<Statement> openStatements;
private final FastStatementList openStatements;
private final HikariPool parentPool;
private boolean isClosed;
@ -63,8 +61,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
SQL_ERRORS.add("57P03"); // CANNOT CONNECT NOW
SQL_ERRORS.add("57P02"); // CRASH SHUTDOWN
SQL_ERRORS.add("01002"); // SQL92 disconnect error
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
protected ConnectionProxy(HikariPool pool, Connection connection)
@ -73,7 +69,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
this.delegate = connection;
creationTime = lastAccess = System.currentTimeMillis();
openStatements = new FastList<Statement>();
openStatements = new FastStatementList();
}
public final void unregisterStatement(Object statement)
@ -409,61 +405,61 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private final Statement __createStatement() throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement());
return ProxyFactory.getProxyStatement(this, delegate.createStatement());
}
private final Statement __createStatement(int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency));
return ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency));
}
private final Statement __createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
return ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
}
private final CallableStatement __prepareCall(String sql) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql));
return ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql));
}
private final CallableStatement __prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency));
return ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency));
}
private final CallableStatement __prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
return ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
private final PreparedStatement __prepareStatement(String sql) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
}
private final PreparedStatement __prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
}
private final PreparedStatement __prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency));
}
private final PreparedStatement __prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
}
private final PreparedStatement __prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
}
private final PreparedStatement __prepareStatement(String sql, String[] columnNames) throws SQLException
{
return PROXY_FACTORY.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
return ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
}
}

@ -31,16 +31,16 @@ import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.Modifier;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.util.ClassLoaderUtils;
/**
*
* @author Brett Wooldridge
*/
public final class JavassistProxyFactoryFactory
public final class JavassistProxyFactory
{
private static final ProxyFactory proxyFactory;
private ClassPool classPool;
static
@ -48,11 +48,10 @@ public final class JavassistProxyFactoryFactory
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(JavassistProxyFactoryFactory.class.getClassLoader());
Thread.currentThread().setContextClassLoader(JavassistProxyFactory.class.getClassLoader());
JavassistProxyFactoryFactory proxyFactoryFactory = new JavassistProxyFactoryFactory();
proxyFactory = proxyFactoryFactory.generateProxyFactory();
JavassistProxyFactory proxyFactoryFactory = new JavassistProxyFactory();
proxyFactoryFactory.modifyProxyFactory();
}
catch (Exception e)
{
@ -64,7 +63,12 @@ public final class JavassistProxyFactoryFactory
}
}
private JavassistProxyFactoryFactory()
public static void initialize()
{
// simply invoking this method causes the initialization of this class.
}
private JavassistProxyFactory()
{
classPool = new ClassPool();
classPool.importPackage("java.sql");
@ -89,51 +93,43 @@ public final class JavassistProxyFactoryFactory
}
}
public static ProxyFactory getProxyFactory()
{
return proxyFactory;
}
private ProxyFactory generateProxyFactory() throws Exception
private void modifyProxyFactory() throws Exception
{
String packageName = ProxyFactory.class.getPackage().getName();
CtClass targetCt = classPool.makeClass(packageName + ".JavassistProxyFactory");
CtClass superCt = classPool.getCtClass(ProxyFactory.class.getName());
targetCt.setSuperclass(superCt);
targetCt.setModifiers(Modifier.FINAL);
for (CtMethod intfMethod : superCt.getDeclaredMethods())
String packageName = JavassistProxyFactory.class.getPackage().getName();
CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.proxy.ProxyFactory");
for (CtMethod method : proxyCt.getMethods())
{
CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null);
StringBuilder call = new StringBuilder("{");
if ("getProxyConnection".equals(method.getName()))
{
call.append("return new ").append(packageName).append(".ConnectionJavassistProxy($$);");
}
if ("getProxyStatement".equals(method.getName()))
else if ("getProxyStatement".equals(method.getName()))
{
call.append("return new ").append(packageName).append(".StatementJavassistProxy($$);");
}
if ("getProxyPreparedStatement".equals(method.getName()))
else if ("getProxyPreparedStatement".equals(method.getName()))
{
call.append("return new ").append(packageName).append(".PreparedStatementJavassistProxy($$);");
}
if ("getProxyResultSet".equals(method.getName()))
else if ("getProxyResultSet".equals(method.getName()))
{
call.append("return $2 != null ? new ").append(packageName).append(".ResultSetJavassistProxy($$) : null;");
}
if ("getProxyCallableStatement".equals(method.getName()))
else if ("getProxyCallableStatement".equals(method.getName()))
{
call.append("return new ").append(packageName).append(".CallableStatementJavassistProxy($$);");
}
else
{
continue;
}
call.append('}');
method.setBody(call.toString());
targetCt.addMethod(method);
}
Class<?> clazz = targetCt.toClass(classPool.getClassLoader(), null);
return (ProxyFactory) clazz.newInstance();
proxyCt.toClass(classPool.getClassLoader(), null);
}
/**
@ -198,6 +194,11 @@ public final class JavassistProxyFactoryFactory
}
}
if (LoggerFactory.getLogger(getClass()).isDebugEnabled())
{
targetCt.debugWriteFile(System.getProperty("java.io.tmpdir"));
}
return targetCt.toClass(classPool.getClassLoader(), null);
}
}

@ -25,20 +25,39 @@ import java.sql.Statement;
import com.zaxxer.hikari.HikariPool;
/**
* This class defines the interface for generating proxies, the
* real (concrete) class is actually generated by Javassist.
* Injected proxy factory class.
*
* @author Brett Wooldridge
*/
public abstract class ProxyFactory
public final class ProxyFactory
{
public abstract Connection getProxyConnection(HikariPool pool, Connection connection);
public abstract Statement getProxyStatement(ConnectionProxy connection, Statement statement);
public abstract CallableStatement getProxyCallableStatement(ConnectionProxy connection, CallableStatement statement);
public abstract PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement);
public abstract ResultSet getProxyResultSet(StatementProxy statement, ResultSet resultSet);
public static Connection getProxyConnection(HikariPool pool, Connection connection)
{
// Body is injected by JavassistProxyFactory
return null;
}
static Statement getProxyStatement(ConnectionProxy connection, Statement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static CallableStatement getProxyCallableStatement(ConnectionProxy connection, CallableStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement)
{
// Body is injected by JavassistProxyFactory
return null;
}
static ResultSet getProxyResultSet(StatementProxy statement, ResultSet resultSet)
{
// Body is injected by JavassistProxyFactory
return null;
}
}

@ -28,18 +28,11 @@ import java.sql.Statement;
*/
public abstract class StatementProxy implements Statement
{
protected static final ProxyFactory PROXY_FACTORY;
protected final IHikariConnectionProxy connection;
protected final Statement delegate;
private boolean isClosed;
static
{
PROXY_FACTORY = JavassistProxyFactoryFactory.getProxyFactory();
}
protected StatementProxy(IHikariConnectionProxy connection, Statement statement)
{
this.connection = connection;
@ -55,7 +48,7 @@ public abstract class StatementProxy implements Statement
{
if (resultSet != null)
{
return PROXY_FACTORY.getProxyResultSet(this, resultSet);
return ProxyFactory.getProxyResultSet(this, resultSet);
}
return null;

@ -16,24 +16,26 @@
package com.zaxxer.hikari.util;
import java.sql.Statement;
/**
* Fast list without range checking.
*
* @author Brett Wooldridge
*/
public class FastList<E>
public final class FastStatementList
{
private transient Object[] elementData;
private Statement[] elementData;
private int size;
/**
* Construct a FastList with a default size of 16.
*/
public FastList()
public FastStatementList()
{
this.elementData = new Object[16];
this.elementData = new Statement[16];
}
/**
@ -41,9 +43,9 @@ public class FastList<E>
*
* @param size the initial size of the FastList
*/
public FastList(int size)
public FastStatementList(int size)
{
this.elementData = new Object[size];
this.elementData = new Statement[size];
}
/**
@ -51,7 +53,7 @@ public class FastList<E>
*
* @param element the element to add
*/
public void add(E element)
public void add(Statement element)
{
if (size < elementData.length)
{
@ -62,7 +64,7 @@ public class FastList<E>
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
Object[] newElementData = new Object[newCapacity];
Statement[] newElementData = new Statement[newCapacity];
System.arraycopy(element, 0, newElementData, 0, oldCapacity);
newElementData[size++] = element;
elementData = newElementData;
@ -75,15 +77,15 @@ public class FastList<E>
* @param index the index of the element to get
* @return the element, or ArrayIndexOutOfBounds is thrown if the index is invalid
*/
@SuppressWarnings("unchecked")
public E get(int index)
public Statement get(int index)
{
return (E) elementData[index];
return elementData[index];
}
/**
* This remove method is most efficient when the element being removed
* is the last element. Equality is identity based, not equals() based.
* Only the first matching element is removed.
*
* @param element the element to remove
*/
Loading…
Cancel
Save