Be defensive when clearing caches for restart
Update `Restarter` to be much more defensive when attempting to clear caches. We now use `clearCache()` methods whenever possible, and only fall back to field access when absolutely necessary. In addition field access now ignore any exceptions. Fixes gh-12719
This commit is contained in:
parent
4e0afaf4c2
commit
ecfc8d73f1
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2016 the original author or authors.
|
* Copyright 2012-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -341,16 +341,47 @@ public class Restarter {
|
||||||
private void cleanupKnownCaches() throws Exception {
|
private void cleanupKnownCaches() throws Exception {
|
||||||
// Whilst not strictly necessary it helps to cleanup soft reference caches
|
// Whilst not strictly necessary it helps to cleanup soft reference caches
|
||||||
// early rather than waiting for memory limits to be reached
|
// early rather than waiting for memory limits to be reached
|
||||||
clear(ResolvableType.class, "cache");
|
clearResolvableTypeCache();
|
||||||
clear("org.springframework.core.SerializableTypeWrapper", "cache");
|
clearCachedIntrospectionResultsCache();
|
||||||
|
clearReflectionUtilsCache();
|
||||||
|
clearAnnotationUtilsCache();
|
||||||
|
clear("com.sun.naming.internal.ResourceManager", "propertiesCache");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearResolvableTypeCache() throws Exception {
|
||||||
|
try {
|
||||||
|
ResolvableType.clearCache();
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
clear(ResolvableType.class, "cache");
|
||||||
|
clear("org.springframework.core.SerializableTypeWrapper", "cache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearCachedIntrospectionResultsCache() throws Exception {
|
||||||
clear(CachedIntrospectionResults.class, "acceptedClassLoaders");
|
clear(CachedIntrospectionResults.class, "acceptedClassLoaders");
|
||||||
clear(CachedIntrospectionResults.class, "strongClassCache");
|
clear(CachedIntrospectionResults.class, "strongClassCache");
|
||||||
clear(CachedIntrospectionResults.class, "softClassCache");
|
clear(CachedIntrospectionResults.class, "softClassCache");
|
||||||
clear(ReflectionUtils.class, "declaredFieldsCache");
|
}
|
||||||
clear(ReflectionUtils.class, "declaredMethodsCache");
|
|
||||||
clear(AnnotationUtils.class, "findAnnotationCache");
|
private void clearReflectionUtilsCache() throws Exception {
|
||||||
clear(AnnotationUtils.class, "annotatedInterfaceCache");
|
try {
|
||||||
clear("com.sun.naming.internal.ResourceManager", "propertiesCache");
|
ReflectionUtils.clearCache();
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
clear(ReflectionUtils.class, "declaredFieldsCache");
|
||||||
|
clear(ReflectionUtils.class, "declaredMethodsCache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearAnnotationUtilsCache() throws Exception {
|
||||||
|
try {
|
||||||
|
AnnotationUtils.clearCache();
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
clear(AnnotationUtils.class, "findAnnotationCache");
|
||||||
|
clear(AnnotationUtils.class, "annotatedInterfaceCache");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear(String className, String fieldName) {
|
private void clear(String className, String fieldName) {
|
||||||
|
|
@ -363,22 +394,28 @@ public class Restarter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clear(Class<?> type, String fieldName) throws Exception {
|
private void clear(Class<?> type, String fieldName) throws Exception {
|
||||||
Field field = type.getDeclaredField(fieldName);
|
try {
|
||||||
field.setAccessible(true);
|
Field field = type.getDeclaredField(fieldName);
|
||||||
Object instance = field.get(null);
|
field.setAccessible(true);
|
||||||
if (instance instanceof Set) {
|
Object instance = field.get(null);
|
||||||
((Set<?>) instance).clear();
|
if (instance instanceof Set) {
|
||||||
}
|
((Set<?>) instance).clear();
|
||||||
if (instance instanceof Map) {
|
|
||||||
Map<?, ?> map = ((Map<?, ?>) instance);
|
|
||||||
for (Iterator<?> iterator = map.keySet().iterator(); iterator.hasNext();) {
|
|
||||||
Object value = iterator.next();
|
|
||||||
if (value instanceof Class && ((Class<?>) value)
|
|
||||||
.getClassLoader() instanceof RestartClassLoader) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (instance instanceof Map) {
|
||||||
|
Map<?, ?> map = ((Map<?, ?>) instance);
|
||||||
|
for (Iterator<?> iterator = map.keySet().iterator(); iterator
|
||||||
|
.hasNext();) {
|
||||||
|
Object value = iterator.next();
|
||||||
|
if (value instanceof Class && ((Class<?>) value)
|
||||||
|
.getClassLoader() instanceof RestartClassLoader) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue