Skip to content

Commit

Permalink
Deregister JDBC drivers when deployed war's ServletContext is destroyed
Browse files Browse the repository at this point in the history
Closes gh-21221
  • Loading branch information
wilkinsona committed May 13, 2020
1 parent 9e569cf commit 8b6cdbb
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
Expand Up @@ -16,6 +16,9 @@

package org.springframework.boot.web.servlet.support;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;

import javax.servlet.Filter;
Expand Down Expand Up @@ -98,14 +101,47 @@ public void contextInitialized(ServletContextEvent event) {
// no-op because the application context is already initialized
}

@Override
public void contextDestroyed(ServletContextEvent event) {
try {
super.contextDestroyed(event);
}
finally {
deregisterJdbcDrivers(event.getServletContext());
}
}

});

}
else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not "
+ "return an application context");
}
}

/**
* Deregisters the JDBC drivers that were registered by the application represented by
* the given {@code servletContext}. The default implementation
* {@link DriverManager#deregisterDriver(Driver) deregisters} every {@link Driver}
* that was loaded by the {@link ServletContext#getClassLoader web application's class
* loader}.
* @param servletContext the web application's servlet context
* @since 2.3.0
*/
protected void deregisterJdbcDrivers(ServletContext servletContext) {
for (Driver driver : Collections.list(DriverManager.getDrivers())) {
if (driver.getClass().getClassLoader() == servletContext.getClassLoader()) {
try {
DriverManager.deregisterDriver(driver);
}
catch (SQLException ex) {
// Continue
}
}
}
}

protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
SpringApplicationBuilder builder = createSpringApplicationBuilder();
builder.main(getClass());
Expand Down
Expand Up @@ -17,12 +17,18 @@
package org.springframework.boot.web.servlet.support;

import java.util.Collections;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
Expand All @@ -46,6 +52,7 @@
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* Tests for {@link SpringBootServletInitializer}.
Expand Down Expand Up @@ -142,6 +149,31 @@ void servletContextPropertySourceIsAvailablePriorToRefresh() {
}
}

@Test
void whenServletContextIsDestroyedThenJdbcDriversAreDeregistered() throws ServletException {
ServletContext servletContext = mock(ServletContext.class);
given(servletContext.getInitParameterNames()).willReturn(new Vector<String>().elements());
given(servletContext.getAttributeNames()).willReturn(new Vector<String>().elements());
AtomicBoolean driversDeregistered = new AtomicBoolean();
new SpringBootServletInitializer() {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Config.class);
}

@Override
protected void deregisterJdbcDrivers(ServletContext servletContext) {
driversDeregistered.set(true);
}

}.onStartup(servletContext);
ArgumentCaptor<ServletContextListener> captor = ArgumentCaptor.forClass(ServletContextListener.class);
verify(servletContext).addListener(captor.capture());
captor.getValue().contextDestroyed(new ServletContextEvent(servletContext));
assertThat(driversDeregistered).isTrue();
}

static class PropertySourceVerifyingSpringBootServletInitializer extends SpringBootServletInitializer {

@Override
Expand Down

0 comments on commit 8b6cdbb

Please sign in to comment.