OSGI & Apache Commons-DBCP Classloading Issue
I inherited some code that is using the Apache commons-dbcp Connection pools in an OSGi bundle. This code works fine with Eclipse/Equinox OSGi version 3.4.3 (R34x_v20081215), commons-dbcp 1.2.2 and the postgres jdbc3 8.3.603 bundles from springsource.org.
I wanted to modernize, maybe this was my first mistake!
When I use the new version of Felix or Equinox OSGI Cores with the new postgresql JDBC3 or JDBC4 bundles along with the latest version of commons-dbcp (1.4.1), I am gett开发者_如何学运维ing a classloading issue. I have done numerous searches and found that the commons-dbcp code should have a fix DBCP-214, but it still seems to fail.
I have tried to put the org.postgresql on the commons-dbcp MANIFEST.MF import-package line, but that did not work either.
I wrote a simple test in an activator that first does a basic class.forName() and DriverManager.getConnection(), this works fine, but when I add in BasicDataSource() and setup the connection with BasicDataSource.getConnection(), I get the ClassNotFoundException. See the code example below.
Thanks in Advance for any help, suggestions, ...
Sau!
// This one fails with an exception
public void dsTest() {
BasicDataSource bds = new BasicDataSource();
ClassLoader cl;
try {
logger.debug("ContextClassLoader: {}",
Thread.currentThread().getContextClassLoader().toString());
cl = this.getClass().getClassLoader();
logger.debug("ClassLoader: {}", cl);
if (bds.getDriverClassLoader() != null) {
logger.debug(bds.getDriverClassLoader().toString());
}
// The failure is the same with and with the setDriverClassLoader() line
bds.setDriverClassLoader(cl);
bds.setDriverClassName("org.postgresql.Driver");
bds.setUrl("jdbc:postgresql://127.0.0.1/dbname");
bds.setUsername("user");
bds.setPassword("pword");
Class.forName("org.postgresql.Driver").newInstance();
conn = bds.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM table");
conn.close();
logger.debug("Closed DataSource Test");
} catch (Exception ex) {
ex.printStackTrace();
logger.debug("Exception: {} ", ex.getMessage());
}
}
// This one works
public void managerTest() {
ClassLoader cl;
try {
cl = this.getClass().getClassLoader();
logger.debug("ClassLoader: {}", cl);
Class.forName("org.postgresql.Driver").newInstance();
String url = "jdbc:postgresql://127.0.0.1/dbname";
conn = DriverManager.getConnection(url, "user", "pword");
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM table");
conn.close();
logger.debug("Closed Manger Test");
} catch (Exception ex) {
ex.printStackTrace();
logger.debug("Exception: {} ", ex.getMessage());
}
}
this is due to the fact that the commons-dbcp bundle cannot look at the actual driver class, because of the osgi class loader. The solution to this is to attach a fragment to the commons-dbcp class with Dynamic Import *. The actual headers that you need in your MANIFEST are the following:
Fragment-Host: org.apache.commons.dbcp DynamicImport-Package: *
After this, the code you mentioned worked. Hope this doesnt come too late.
精彩评论