Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.
Пример:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Вы можно просто избежать этого, проверив, является ли переменная не нулевой:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .
Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!
Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
Типы значений (вы можете просто игнорировать эти):
Начиная с версии 6.0.24, Tomcat поставляется с функцией обнаружения утечки памяти , что, в свою очередь, может привести к появлению подобных предупреждающих сообщений, когда в файле [app1] для веб-сервера есть JDBC 4.0-совместимый драйвер, auto- регистрирует сам во время запуска webapp, используя ServiceLoader
API , но который сам не отключился deregister во время отключения Webapp. Это сообщение является чисто неофициальным, Tomcat уже принял меры по предотвращению утечки памяти.
Что вы можете сделать?
/WEB-INF/lib
, но только на сервере /lib
. Если вы все еще сохраняете его в файле /WEB-INF/lib
в webapp, вам необходимо зарегистрировать его вручную и отменить его с помощью ServletContextListener
. OutOfMemoryError
во время горячих рассылок Tomcat. /lib
Tomcat и подключите пул данных к источнику данных для управления драйвером. Обратите внимание, что встроенный DBCP от Tomcat не отменяет регистрацию драйверов должным образом при закрытии. См. Также ошибку DBCP-322 , которая закрыта как WONTFIX. Вы хотели бы заменить DBCP другим пулом соединений, который лучше выполняет свою работу, чем DBCP. Например, HikariCP , BoneCP или, возможно, Tomcat JDBC Pool . В вашем контексте контекст-слушатель контекстного методаDestroyed () вручную отмените регистрацию драйверов:
// This manually deregisters JDBC driver, which prevents Tomcat 7 from complaining about memory leaks wrto this class
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
LOG.log(Level.INFO, String.format("deregistering jdbc driver: %s", driver));
} catch (SQLException e) {
LOG.log(Level.SEVERE, String.format("Error deregistering driver %s", driver), e);
}
}
Я столкнулся с этой проблемой, когда я развертывал приложение Grails на AWS. Это вопрос драйвера JDBC по умолчанию для драйвера org.h2. Как вы можете видеть это в Datasource.groovy внутри вашей папки конфигурации. Как вы можете видеть ниже:
dataSource {
pooled = true
jmxExport = true
driverClassName = "org.h2.Driver" // make this one comment
username = "sa"
password = ""
}
Прокомментируйте эти строки везде, где упоминается org.h2.Driver в файле datasource.groovy, если вы не используете эту базу данных. В противном случае вам нужно загрузить этот файл jar базы данных.
Спасибо.
Это прослушиватель, который я написал для решения проблемы: он автоматически определяет, был ли водитель зарегистрирован и действует соответственно .it
Важно: это должен использоваться ТОЛЬКО, когда баннер драйвера развертывается в WEB-INF / lib, а не в Tomcat / lib, как многие из них предлагают, так что каждое приложение может позаботиться о своем собственном драйвере и запустить на нетронутом Tomcat. Таким образом, это должно быть IMHO.
Просто настройте слушателя в вашем web.xml перед любым другим и наслаждайтесь.
добавить в верхней части web.xml :
<listener>
<listener-class>utils.db.OjdbcDriverRegistrationListener</listener-class>
</listener>
сохранить как utils / db / OjdbcDriverRegistrationListener.java :
package utils.db;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import oracle.jdbc.OracleDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Registers and unregisters the Oracle JDBC driver.
*
* Use only when the ojdbc jar is deployed inside the webapp (not as an
* appserver lib)
*/
public class OjdbcDriverRegistrationListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory
.getLogger(OjdbcDriverRegistrationListener.class);
private Driver driver = null;
/**
* Registers the Oracle JDBC driver
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
this.driver = new OracleDriver(); // load and instantiate the class
boolean skipRegistration = false;
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver instanceof OracleDriver) {
OracleDriver alreadyRegistered = (OracleDriver) driver;
if (alreadyRegistered.getClass() == this.driver.getClass()) {
// same class in the VM already registered itself
skipRegistration = true;
this.driver = alreadyRegistered;
break;
}
}
}
try {
if (!skipRegistration) {
DriverManager.registerDriver(driver);
} else {
LOG.debug("driver was registered automatically");
}
LOG.info(String.format("registered jdbc driver: %s v%d.%d", driver,
driver.getMajorVersion(), driver.getMinorVersion()));
} catch (SQLException e) {
LOG.error(
"Error registering oracle driver: " +
"database connectivity might be unavailable!",
e);
throw new RuntimeException(e);
}
}
/**
* Deregisters JDBC driver
*
* Prevents Tomcat 7 from complaining about memory leaks.
*/
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
if (this.driver != null) {
try {
DriverManager.deregisterDriver(driver);
LOG.info(String.format("deregistering jdbc driver: %s", driver));
} catch (SQLException e) {
LOG.warn(
String.format("Error deregistering driver %s", driver),
e);
}
this.driver = null;
} else {
LOG.warn("No driver to deregister");
}
}
}
Я обнаружил, что реализация простого метода destroy () для деинсталляции любых драйверов JDBC прекрасно работает.
/**
* Destroys the servlet cleanly by unloading JDBC drivers.
*
* @see javax.servlet.GenericServlet#destroy()
*/
public void destroy() {
String prefix = getClass().getSimpleName() +" destroy() ";
ServletContext ctx = getServletContext();
try {
Enumeration<Driver> drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()) {
DriverManager.deregisterDriver(drivers.nextElement());
}
} catch(Exception e) {
ctx.log(prefix + "Exception caught while deregistering JDBC drivers", e);
}
ctx.log(prefix + "complete");
}
Я нашел ту же проблему с Tomcat версии 6.026.
Я использовал Mysql JDBC.jar в библиотеке WebAPP, а также в TOMCAT Lib.
Чтобы исправить это, удалив Jar из папки TOMCAT lib.
Итак, я понимаю, что TOMCAT правильно обрабатывает утечку памяти JDBC. Но если JSB JQB JQB дублируется в WebApp и Tomcat Lib, Tomcat сможет обрабатывать только банку в папке Tomcat Lib.
Я добавлю к этому что-то, что я нашел на форумах Spring. Если вы переместите JDBC-драйвер в папку tomcat lib, вместо того, чтобы развернуть его с помощью webapp, предупреждение, похоже, исчезнет. Я могу подтвердить, что это сработало для меня
У меня была аналогичная проблема, но дополнительно я получал ошибку Java Heap Space в любое время, когда я модифицировал / сохранил JSP-страницы с сервером Tomcat, поэтому контекст не был полностью перезаряжен.
Мои версии были Apache Tomcat 6.0.29 и JDK 6u12.
Обновление JDK до 6u21, как предлагается в Ссылки в разделе URL http: / /wiki.apache.org/tomcat/MemoryLeakProtection решил проблему Java Heap Space (контекст теперь перезагружает OK), хотя ошибка драйвера JDBC все еще появляется.
Удаляет приложение (tomcat6). Файлы conf сохраняются. Это как-то ломается. Я не уверен, как это делается.
Я вижу, что этот вопрос много. Да, Tomcat 7 автоматически отменяет регистрацию, но это ДЕЙСТВИТЕЛЬНО контролирует ваш код и хорошую практику кодирования? Конечно, вы хотите знать, что у вас есть правильный код, чтобы закрыть все ваши объекты, отключить потоки пула подключений к базе данных и избавиться от всех предупреждений.
Вот как я это делаю.
Шаг 1: зарегистрируйте прослушиватель
web.xml
<listener>
<listener-class>com.mysite.MySpecialListener</listener-class>
</listener>
Шаг 2: Внедрить слушателя
com.mysite.MySpecialListener.java
public class MySpecialListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// On Application Startup, please…
// Usually I'll make a singleton in here, set up my pool, etc.
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// On Application Shutdown, please…
// 1. Go fetch that DataSource
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource datasource = (DataSource)envContext.lookup("jdbc/database");
// 2. Deregister Driver
try {
java.sql.Driver mySqlDriver = DriverManager.getDriver("jdbc:mysql://localhost:3306/");
DriverManager.deregisterDriver(mySqlDriver);
} catch (SQLException ex) {
logger.info("Could not deregister driver:".concat(ex.getMessage()));
}
// 3. For added safety, remove the reference to dataSource for GC to enjoy.
dataSource = null;
}
}
Пожалуйста, не стесняйтесь комментировать и / или добавить ...
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mywebsite</groupId>
<artifactId>emusicstore</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.9</source>
<target>1.9</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
MyWebAppContextListener.java
package com.emusicstore.utils;
import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
public class MyWebAppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("************** Starting up! **************");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("************** Shutting down! **************");
System.out.println("Destroying Context...");
System.out.println("Calling MySQL AbandonedConnectionCleanupThread checkedShutdown");
AbandonedConnectionCleanupThread.checkedShutdown();
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader() == cl) {
try {
System.out.println("Deregistering JDBC driver {}");
DriverManager.deregisterDriver(driver);
} catch (SQLException ex) {
System.out.println("Error deregistering JDBC driver {}");
ex.printStackTrace();
}
} else {
System.out.println("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader");
}
}
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.emusicstore.utils.MyWebAppContextListener</listener-class>
</listener>
<!-- ... -->
</web-app>
Источник , который вдохновил меня на исправление этой ошибки.
Это чисто проблема регистрации / снятия регистрации с сервера в mysql`s driver или tomcats webapp-classloader. Скопируйте mysql-драйвер в папку tomcats lib (так что он загружен jvm напрямую, а не tomcat), и сообщение исчезнет. Это приводит к выгрузке драйвера mysql jdbc только при отключении JVM, и никто не заботится о утечке памяти.
Хотя Tomcat принудительно отменяет регистрацию драйвера JDBC для вас, тем не менее, хорошая практика - очистить все ресурсы, созданные вашим webapp, при уничтожении контекста, если вы перейдете в другой контейнер сервлетов, который не выполняет проверки безопасности утечки памяти, которые Tomcat делает.
Тем не менее, методология полного снятия регистрации водителя опасна. Некоторые драйверы, возвращаемые методом DriverManager.getDrivers()
, возможно, были загружены родительским ClassLoader (то есть загрузчиком классов контейнера сервлетов), а не классом ClassLoader для контекста webapp (например, они могут находиться в папке lib контейнера, а не в веб-папке, и поэтому совместно используются весь контейнер).
Поэтому следует проверить, что ClassLoader для каждого драйвера является ClassLoader Webapp, прежде чем отменять его регистрацию. Итак, в вашем контексте contextTestroyed () метода ContextListener:
public final void contextDestroyed(ServletContextEvent sce) {
// ... First close any background tasks which may be using the DB ...
// ... Then close any DB connection pools ...
// Now deregister JDBC drivers in this context's ClassLoader:
// Get the webapp's ClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// Loop through all drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader() == cl) {
// This driver was registered by the webapp's ClassLoader, so deregister it:
try {
log.info("Deregistering JDBC driver {}", driver);
DriverManager.deregisterDriver(driver);
} catch (SQLException ex) {
log.error("Error deregistering JDBC driver {}", driver, ex);
}
} else {
// driver was not registered by the webapp's ClassLoader and may be in use elsewhere
log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);
}
}
}
Если вы получаете это сообщение от измененного военного изменения Maven, укажите область действия драйвера JDBC и поместите его копию в каталог lib. Например:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
<!-- put a copy in /usr/share/tomcat7/lib -->
<scope>provided</scope>
</dependency>