diff --git a/src/main/java/com/zaxxer/hikari/HikariConfig.java b/src/main/java/com/zaxxer/hikari/HikariConfig.java index 97310a36..d8557b03 100644 --- a/src/main/java/com/zaxxer/hikari/HikariConfig.java +++ b/src/main/java/com/zaxxer/hikari/HikariConfig.java @@ -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 */ diff --git a/src/main/java/com/zaxxer/hikari/HikariPool.java b/src/main/java/com/zaxxer/hikari/HikariPool.java index 966da0be..e4b9aef7 100644 --- a/src/main/java/com/zaxxer/hikari/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/HikariPool.java @@ -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) { diff --git a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index bbd98cb4..e8885c80 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -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)); } } diff --git a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java similarity index 82% rename from src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java rename to src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java index ac6ae306..ef406ce8 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java +++ b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java @@ -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); } } diff --git a/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java b/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java index 277e70b0..ba20ab20 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java +++ b/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java @@ -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; + } } diff --git a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java index 183b705c..056d3c4a 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java @@ -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; diff --git a/src/main/java/com/zaxxer/hikari/util/FastList.java b/src/main/java/com/zaxxer/hikari/util/FastStatementList.java similarity index 85% rename from src/main/java/com/zaxxer/hikari/util/FastList.java rename to src/main/java/com/zaxxer/hikari/util/FastStatementList.java index d89f2d4c..f919fb6f 100644 --- a/src/main/java/com/zaxxer/hikari/util/FastList.java +++ b/src/main/java/com/zaxxer/hikari/util/FastStatementList.java @@ -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 */