Servlet .jar依赖关系空指针 [英] Servlet .jar Dependency Null Pointer
问题描述
我从类路径中列为导出依赖项的.jar文件中获得了一个似乎莫名其妙的nullPointerException。
I am getting a seemingly inexplicable nullPointerException from a .jar file that is listed in the classpath as an export dependency.
jar文件由一个数据库bean组成,该数据库bean在普通的主方法POJO中调用它时,它可以正常工作,但是当我在servlet中调用同一个jar文件时,无论调用什么,我都会从 con.prepareStatement 中获得空指针。
The jar file consists of a database bean that works flawlessly when it is called inside of a normal main method POJO, but when I called the same jar file in a servlet, I get null pointers from the con.prepareStatement of whatever I call.
我认为这可能是导致它的池中的SQLException,因此我将其移至我们的VM服务器,该服务器可以在其云环境中直接与数据库实例进行通信,我出现相同的错误。
I thought that it might be a SQLException from the pool causing it, so I moved it to our VM server where it can talk directly to the database instance across its cloud environment, and I get the same error.
该bean包含四个附加的从属jar文件: guava-16.0.1.jar (用于弱引用哈希表) , postgresql-9.3-1100.jdbc41.jar , tomcat-dbcp.jar , tomcat-jdbc.jar 使用FatJar for Eclipse的单个jar文件,然后将其导入到我的servlet中
The bean consists of four additional dependent jar files: guava-16.0.1.jar(for weak referenced hashmaps), postgresql-9.3-1100.jdbc41.jar, tomcat-dbcp.jar, tomcat-jdbc.jar that are all wrapped up into a single jar file using FatJar for Eclipse, which is then imported into my servlet which is hosted in a Tomcat8 servlet container (also tested in Tomcat7 and TomEE).
该servlet代码如下:
The servlet code is as follows:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.package.DBEngine;
@WebServlet("/PrimaryEngine")
public class PrimaryEngine extends HttpServlet {
private static final long serialVersionUID = 1L;
private DBEngine db;
public void init(ServletConfig config) throws ServletException{
super.init(config);
db = new DBEngine();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
if(request.getParameterMap().containsKey("op")){
out.println("Getting data...");
String test = db.DBdebug();
out.println(test);
return;
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
DBEngine看起来像这样:
The DBEngine looks like this:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import com.google.common.collect.MapMaker;
import com.sun.istack.internal.logging.Logger;
public class DBEngine {
private Pool pool = null;
private Connection con = null;
private PreparedStatement ps = null;
//-------------------------------------------
public DBEngine(){
this.pool = new Pool();
this.con = pool.getConnection();
this.ps = null;
}
//---------------------------------------------------
// Begin subsidiary functions/methods
//---------------------------------------------------
public String DBdebug(){
try {
String ps = "SELECT table_name FROM information_schema.tables";
PreparedStatement ps2 = con.prepareStatement(ps);
ResultSet rs = ps2.executeQuery();
if(rs.next()){
return "Success";
} else return "Fail";
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
tomcat-dbcp池看起来像
The tomcat-dbcp pool looks like this:
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
public class Pool {
private static DataSource datasource = null;
//--------------------------------------------------
// Sets up the database connection pool
//--------------------------------------------------
public Pool() {
PoolProperties p = new PoolProperties();
p.setUrl("jdbc:postgresql://*URL*:5432/*databasename*");
p.setDriverClassName("org.postgresql.Driver");
p.setUsername("*someUserName*");
p.setPassword("*somePassword*");
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(75);
p.setMaxIdle(75);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setRemoveAbandonedTimeout(60);
p.setAbandonWhenPercentageFull(60);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;"+
"org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer");
datasource = new DataSource();
datasource.setPoolProperties(p);
}
//-------------------------------------------------------
// Closes an open datasource
//-------------------------------------------------------
public synchronized void closeDatasource() {
try {
datasource.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//--------------------------------------------------------
// Get a connection
//--------------------------------------------------------
public Connection getConnection() {
try {
return datasource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
堆栈跟踪:
[ajp-nio-8009-exec-3] org.apache.catalina.core.StandardWrapperValve.invoke Allocate exception for servlet com.package.engine.main.PrimaryEngine
java.lang.NullPointerException
com.package.DBEngine.<init>(DBEngine.java:##)
com.package.main.PrimaryEngine.init(PrimaryEngine.java:26)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
org.apache.coyote.ajp.AbstractAjpProcessor.process(AbstractAjpProcessor.java:799)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:651)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:722)
我在这里很机智。我所知道的关于Java的所有信息都说它应该可以,但是不能。
I am at wits end here. Everything that I know about Java says that it should work, but it does not.
编辑:
这是Tomcat输出的唯一其他堆栈跟踪:
This is the only other stack trace that Tomcat outputs:
javax.servlet.ServletException:servlet com.package.main.PrimaryEngine的Servlet.init()抛出异常
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
org.apache.catalina .valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
org.apache.coyote.ajp.AbstractAjpProcessor.process (AbstractAjpProcessor.java:799)
org.apache.coyote.AbstractProtocol $ AbstractConnectionHandler.process(AbstractProtocol.java:651)
org.apache.tomcat.util.net.NioEndpoint $ SocketProcessor.doRun(NioEndpoint .java:1575)
org.apache.tomcat.util.net.NioEndpoin t $ SocketProcessor.run(NioEndpoint.java:1533)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor。 java:615)
java.lang.Thread.run(Thread.java:722)
javax.servlet.ServletException: Servlet.init() for servlet com.package.main.PrimaryEngine threw exception org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74) org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509) org.apache.coyote.ajp.AbstractAjpProcessor.process(AbstractAjpProcessor.java:799) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:651) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575) org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:722)
推荐答案
基于Luiggi的关于不手动在类中创建数据源的建议以及使用JNDI数据库池的建议,我能够获得以下解决方案。
我的改编很大程度上取决于此链接: http://www.codejava.net/servers/tomcat/configuring-jndi-datasource-for-database-connection-pooling-in-tomcat
Based on Luiggi's input regarding not manually creating the datasource in a class and recommendation to use JNDI database pooling, I was able to get the solution below to work. My adaptation is heavily based on this link: http://www.codejava.net/servers/tomcat/configuring-jndi-datasource-for-database-connection-pooling-in-tomcat
部分:Tomcat 8.0,postgresql-jdbc驱动程序,DBEngine bean,servlet
Pieces: Tomcat 8.0, postgresql-jdbc driver, DBEngine bean, servlet
dbEngine bean由三个类组成:DBEngine.java,Pool.java ,以及SQLPS.java(一个SQL语句库),它们都包装到一个jar文件中,并导入到servlet中,并标记为类路径导出依赖项。
The dbEngine bean consists of three classes: DBEngine.java, Pool.java, and SQLPS.java (a SQL statement library) that are all wrapped into one jar file and imported into the servlet and marked as a classpath export dependency.
Servlet调用Bean看起来像这样:
The servlet calling the bean looks like:
package com.engine.main;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentMap;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sslog4java.LogLevel;
import sslog4java.Logger;
import com.google.gson.Gson;
import com.DBbean.DBEngine;
@WebServlet("/PrimaryEngine")
public class PrimaryEngine extends HttpServlet {
private static final long serialVersionUID = 1L;
private DBEngine db = null;
private static String filePath = "";
private static String fileName = "";
Logger fLogger = null;
public void init(ServletConfig config) throws ServletException{
super.init(config);
ServletContext scxt = config.getServletContext();
filePath = scxt.getRealPath("/WEB-INF") + "\\logs\\";
fileName = "loggerFileName";
fLogger = new Logger(filePath, fileName, LogLevel.DEBUG);
try {
// passed the servlet context into the DBengine for the pool to use
db = new DBEngine(new InitialContext(), fLogger);
} catch (SQLException | NamingException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
if(request.getParameterMap().containsKey("param") && request.getParameter("param").equals("paramValue")){
test = db.DBdebug();
out.println(test);
return;
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
dbEngine.java看起来像:
The dbEngine.java looks like:
package com.DBbean;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import javax.naming.Context;
import sslog4java.Logger;
import com.google.common.collect.MapMaker;
public class DBEngine {
private Pool pool = null;
private Connection con = null;
private Logger fLogger;
public DBEngine(Context initCtx, Logger logr) throws SQLException{
this.fLogger = logr;
// passed the servlet context into the Pool.java
this.pool = new Pool(initCtx);
this.con = pool.getConnection();
}
public String DBdebug(){
Connection conn = pool.getConnection();
try {
String ps = SQLPS.debugSQL;
PreparedStatement ps2 = conn.prepareStatement(ps);
ResultSet rs = ps2.executeQuery();
if(rs.next()){
return "Success";
} else return "Fail";
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
Pool.java如下:
and the Pool.java looks like:
package com.DBbean;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class Pool {
Context ctx;
public Pool(Context context){
ctx = context;
}
public Connection getConnection() {
try {
DataSource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/postgres4" );
return ds.getConnection();
} catch (SQLException | NamingException sne) {
sne.printStackTrace();
return null;
}
}
}
我必须添加以下行到$ CATALINA_HOME / conf / context.xml:
I had to add these lines to the $CATALINA_HOME/conf/context.xml:
<Resource
name="jdbc/postgres4"
auth="Container"
type="javax.sql.DataSource"
maxActive="8"
maxIdle="8"
driverClassName="org.postgresql.Driver"
url="*URL*"
username="*UserName*"
password="*Password*"
/>
并将这些行发送到$ CATALINA_HOME / conf / web.xml:
and these lines to $CATALINA_HOME/conf/web.xml:
<resource-ref>
<description>postgreSQL Datasource</description>
<res-ref-name>jdbc/postgres4</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
和postgresql-jdbc jar放入$ CATALINA_HOME / lib
and the postgresql-jdbc jar went into $CATALINA_HOME/lib
这篇关于Servlet .jar依赖关系空指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!