diff --git a/changelog.html b/changelog.html
index 720e40835d..5e4881d307 100644
--- a/changelog.html
+++ b/changelog.html
@@ -64,6 +64,9 @@ Upcoming changes
Allow BuildStep to work with non-AbstractProject
(issue 23713)
+
+ Improved class loading performance when using Groovy.
+ (issue 24309)
Make the lifetime of queue items cache configurable.
(issue 19691)
diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java
index d47ac923c8..36f4880f77 100644
--- a/core/src/main/java/hudson/PluginManager.java
+++ b/core/src/main/java/hudson/PluginManager.java
@@ -435,6 +435,9 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
plugins.add(p);
activePlugins.add(p);
+ synchronized (((UberClassLoader) uberClassLoader).loaded) {
+ ((UberClassLoader) uberClassLoader).loaded.clear();
+ }
try {
p.resolvePluginDependencies();
@@ -1015,6 +1018,8 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
* Keyed by the generated class name.
*/
private ConcurrentMap> generatedClasses = new ConcurrentHashMap>();
+ /** Cache of loaded, or known to be unloadable, classes. */
+ private final Map> loaded = new HashMap>();
public UberClassLoader() {
super(PluginManager.class.getClassLoader());
@@ -1033,13 +1038,35 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
else generatedClasses.remove(name,wc);
}
+ if (name.startsWith("SimpleTemplateScript")) { // cf. groovy.text.SimpleTemplateEngine
+ throw new ClassNotFoundException("ignoring " + name);
+ }
+ synchronized (loaded) {
+ if (loaded.containsKey(name)) {
+ Class> c = loaded.get(name);
+ if (c != null) {
+ return c;
+ } else {
+ throw new ClassNotFoundException("cached miss for " + name);
+ }
+ }
+ }
if (FAST_LOOKUP) {
for (PluginWrapper p : activePlugins) {
try {
Class> c = ClassLoaderReflectionToolkit._findLoadedClass(p.classLoader, name);
- if (c!=null) return c;
+ if (c != null) {
+ synchronized (loaded) {
+ loaded.put(name, c);
+ }
+ return c;
+ }
// calling findClass twice appears to cause LinkageError: duplicate class def
- return ClassLoaderReflectionToolkit._findClass(p.classLoader, name);
+ c = ClassLoaderReflectionToolkit._findClass(p.classLoader, name);
+ synchronized (loaded) {
+ loaded.put(name, c);
+ }
+ return c;
} catch (ClassNotFoundException e) {
//not found. try next
}
@@ -1053,6 +1080,9 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
}
}
}
+ synchronized (loaded) {
+ loaded.put(name, null);
+ }
// not found in any of the classloader. delegate.
throw new ClassNotFoundException(name);
}