I'm using Jetty 9.2 (embedded) with the standard MySQL connector API and I'm very confused by how this is supposed to be setup. Currently, I have this in my web.xml file:
JDBC Data Source
jdbc/DataSource
javax.sql.DataSource
Container
...and this in my jetty-env.xml:
jdbc/DataSource
jdbc:mysql://localhost:3306/DBName
user
pass
...and this code to initialize:
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
DataSource datasource = (DataSource) envCtx.lookup("jdbc/DataSource");
When I try to fire up the server, I get the error javax.naming.NameNotFoundException; remaining name 'jdbc/DataSource'. I've tried lots of different variations of the strings in the code initialization, like removing the lookup call on the InitialContext object, but I just keep getting variations of the same error with a different name value;
Both of the xml files are located in my /WAR/WEB-INF directory. I've looked at loads of previous questions and tutorials, blogs etc. but I'm getting nowhere.
解决方案
It was a combination of problems specific to embedded Jetty.
First, my launcher code that was configuring and launching the web server was doing the JNDI lookup before I actually started the web server i.e. before calling server.start(), so the JNDI configuration was not initialized at that stage.
But even making this change didn't work, because the envCtx.lookup("jdbc/DataSource") needs to be called from a thread that's associated with the WebApp. So I moved that code to a static block that gets called the first time a database connection is requested by a web server request.
In the end, I ended up with something like this for my launcher code:
public static void main(String[] args) {
Server server = new Server();
//Enable parsing of jndi-related parts of web.xml and jetty-env.xml
ClassList classlist = ClassList.setServerDefault(server);
classlist.addAfter(
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.plus.webapp.EnvConfiguration",
"org.eclipse.jetty.plus.webapp.PlusConfiguration");
...
...
server.start();
The JNDI lookup cannot be made by this main thread, so put it somewhere like the init method of a servlet request, or like I did, a synchronized method of a static database accessor class that gets used by servlets e.g.
public class DatabaseUtils {
private static DataSource datasource;
private static synchronized Connection getDBConnection() throws SQLException {
if (datasource == null) {
initDataSource();
}
return datasource.getConnection();
}
public static void initDataSource() {
try {
datasource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/DataSource");
LOG.info("Database connection pool initalized successfully");
} catch (Exception e) {
LOG.error("Error while initialising the database connection pool", e);
}
}