diff --git a/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java b/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java index 1f17f45719b..c4e228c3c1e 100644 --- a/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java +++ b/spring-context/src/main/java/org/springframework/context/support/ContextTypeMatchClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import java.security.ProtectionDomain; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.apache.commons.logging.LogFactory; + import org.springframework.core.DecoratingClassLoader; import org.springframework.core.OverridingClassLoader; import org.springframework.core.SmartClassLoader; @@ -45,15 +47,26 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart } - private static Method findLoadedClassMethod; + @Nullable + private static final Method findLoadedClassMethod; static { + // Try to enable findLoadedClass optimization which allows us to selectively + // override classes that have not been loaded yet. If not accessible, we will + // always override requested classes, even when the classes have been loaded + // by the parent ClassLoader already and cannot be transformed anymore anyway. + Method method = null; try { - findLoadedClassMethod = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); + method = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); + ReflectionUtils.makeAccessible(method); } - catch (NoSuchMethodException ex) { - throw new IllegalStateException("Invalid [java.lang.ClassLoader] class: no 'findLoadedClass' method defined!"); + catch (Throwable ex) { + // Typically a JDK 9+ InaccessibleObjectException... + // Avoid through JVM startup with --add-opens=java.base/java.lang=ALL-UNNAMED + LogFactory.getLog(ContextTypeMatchClassLoader.class).debug( + "ClassLoader.findLoadedClass not accessible -> will always override requested class", ex); } + findLoadedClassMethod = method; } @@ -96,13 +109,14 @@ class ContextTypeMatchClassLoader extends DecoratingClassLoader implements Smart if (isExcluded(className) || ContextTypeMatchClassLoader.this.isExcluded(className)) { return false; } - ReflectionUtils.makeAccessible(findLoadedClassMethod); - ClassLoader parent = getParent(); - while (parent != null) { - if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) { - return false; + if (findLoadedClassMethod != null) { + ClassLoader parent = getParent(); + while (parent != null) { + if (ReflectionUtils.invokeMethod(findLoadedClassMethod, parent, className) != null) { + return false; + } + parent = parent.getParent(); } - parent = parent.getParent(); } return true; }