Browse Source

Cache Class.getDeclaredMethods() results and avoid pattern matching in isCglibRenamedMethod as far as possible

Issue: SPR-11882
Issue: SPR-11894
pull/579/head
Juergen Hoeller 12 years ago
parent
commit
5f695a47db
  1. 44
      spring-core/src/main/java/org/springframework/util/ReflectionUtils.java

44
spring-core/src/main/java/org/springframework/util/ReflectionUtils.java

@ -26,6 +26,7 @@ import java.sql.SQLException; @@ -26,6 +26,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
@ -44,11 +45,23 @@ import java.util.regex.Pattern; @@ -44,11 +45,23 @@ import java.util.regex.Pattern;
*/
public abstract class ReflectionUtils {
/**
* Naming prefix for CGLIB-renamed methods.
* @see #isCglibRenamedMethod
*/
private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$";
/**
* Pattern for detecting CGLIB-renamed methods.
* @see #isCglibRenamedMethod
*/
private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern.compile("CGLIB\\$(.+)\\$\\d+");
private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern.compile("(.+)\\$\\d+");
/**
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast resolution.
*/
private static final Map<Class<?>, Method[]> declaredMethodsCache =
new ConcurrentReferenceHashMap<Class<?>, Method[]>(256);
/**
@ -156,7 +169,7 @@ public abstract class ReflectionUtils { @@ -156,7 +169,7 @@ public abstract class ReflectionUtils {
Assert.notNull(name, "Method name must not be null");
Class<?> searchType = clazz;
while (searchType != null) {
Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType));
for (Method method : methods) {
if (name.equals(method.getName()) &&
(paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {
@ -397,7 +410,9 @@ public abstract class ReflectionUtils { @@ -397,7 +410,9 @@ public abstract class ReflectionUtils {
* @see org.springframework.cglib.proxy.Enhancer#rename
*/
public static boolean isCglibRenamedMethod(Method renamedMethod) {
return CGLIB_RENAMED_METHOD_PATTERN.matcher(renamedMethod.getName()).matches();
String name = renamedMethod.getName();
return (name.startsWith(CGLIB_RENAMED_METHOD_PREFIX) &&
CGLIB_RENAMED_METHOD_PATTERN.matcher(name.substring(CGLIB_RENAMED_METHOD_PREFIX.length())).matches());
}
/**
@ -424,8 +439,8 @@ public abstract class ReflectionUtils { @@ -424,8 +439,8 @@ public abstract class ReflectionUtils {
* @see java.lang.reflect.Method#setAccessible
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) &&
!method.isAccessible()) {
method.setAccessible(true);
}
}
@ -439,8 +454,8 @@ public abstract class ReflectionUtils { @@ -439,8 +454,8 @@ public abstract class ReflectionUtils {
* @see java.lang.reflect.Constructor#setAccessible
*/
public static void makeAccessible(Constructor<?> ctor) {
if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))
&& !ctor.isAccessible()) {
if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) &&
!ctor.isAccessible()) {
ctor.setAccessible(true);
}
}
@ -471,7 +486,7 @@ public abstract class ReflectionUtils { @@ -471,7 +486,7 @@ public abstract class ReflectionUtils {
throws IllegalArgumentException {
// Keep backing up the inheritance hierarchy.
Method[] methods = clazz.getDeclaredMethods();
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
if (mf != null && !mf.matches(method)) {
continue;
@ -546,6 +561,19 @@ public abstract class ReflectionUtils { @@ -546,6 +561,19 @@ public abstract class ReflectionUtils {
return methods.toArray(new Method[methods.size()]);
}
/**
* This method retrieves {@link Class#getDeclaredMethods()} from a local cache
* in order to avoid the JVM's SecurityManager check and defensive array copying.
*/
private static Method[] getDeclaredMethods(Class<?> clazz) {
Method[] result = declaredMethodsCache.get(clazz);
if (result == null) {
result = clazz.getDeclaredMethods();
declaredMethodsCache.put(clazz, result);
}
return result;
}
/**
* Invoke the given callback on all fields in the target class, going up the
* class hierarchy to get all declared fields.

Loading…
Cancel
Save