Fix for problem with cglib proxies in spring boot apps
This commit is contained in:
@@ -273,7 +273,7 @@ public class ReloadableType {
|
||||
*/
|
||||
public boolean loadNewVersion(String versionsuffix, byte[] newbytedata) {
|
||||
javaMethodCache = null;
|
||||
if (log.isLoggable(Level.INFO)) {
|
||||
if (GlobalConfiguration.verboseMode && log.isLoggable(Level.INFO)) {
|
||||
log.info("Loading new version of "+slashedtypename+", identifying suffix "+versionsuffix+", new data length is "+newbytedata.length+"bytes");
|
||||
}
|
||||
|
||||
@@ -454,6 +454,12 @@ public class ReloadableType {
|
||||
ReloadableType proxy = typeRegistry.cglibProxies.get(this.slashedtypename);
|
||||
if (proxy != null) {
|
||||
Object[] strategyAndGeneratorPair = CglibPluginCapturing.clazzToGeneratorStrategyAndClassGeneratorMap.get(getClazz());
|
||||
if (strategyAndGeneratorPair == null) {
|
||||
if (log.isLoggable(Level.SEVERE)) {
|
||||
log.severe("Unable to find regeneration methods for cglib proxies - proxies will be out of date for this type");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Object a = strategyAndGeneratorPair[0];
|
||||
Object b = strategyAndGeneratorPair[1];
|
||||
// want to call a.generate(b)
|
||||
|
||||
@@ -28,18 +28,25 @@ import org.springsource.loaded.LoadtimeInstrumentationPlugin;
|
||||
*/
|
||||
public class CglibPlugin implements LoadtimeInstrumentationPlugin {
|
||||
|
||||
// private static Logger log = Logger.getLogger(CglibPlugin.class.getName());
|
||||
// private static Logger log = Logger.getLogger(CglibPlugin.class.getName());
|
||||
|
||||
// implementing LoadtimeInstrumentationPlugin
|
||||
public boolean accept(String slashedTypeName, ClassLoader classLoader, ProtectionDomain protectionDomain, byte[] bytes) {
|
||||
if (slashedTypeName==null) {
|
||||
return false;
|
||||
}
|
||||
return slashedTypeName.equals("net/sf/cglib/core/AbstractClassGenerator");
|
||||
// if (slashedTypeName.contains("cglib")) {
|
||||
// System.out.println(">>CglibPlugin.accept("+slashedTypeName+")");
|
||||
// }
|
||||
// Seen in the wild:
|
||||
// net/sf/cglib/core/AbstractClassGenerator
|
||||
// org/springframework/cglib/core/AbstractClassGenerator
|
||||
return slashedTypeName.endsWith("/cglib/core/AbstractClassGenerator");
|
||||
// || slashedTypeName.equals("net/sf/cglib/reflect/FastClass");
|
||||
}
|
||||
|
||||
public byte[] modify(String slashedClassName, ClassLoader classLoader, byte[] bytes) {
|
||||
System.out.println(">> CglibPlugin.modify("+slashedClassName+","+classLoader+","+bytes.length);
|
||||
// if (slashedClassName.equals("net/sf/cglib/core/AbstractClassGenerator")) {
|
||||
return CglibPluginCapturing.catchGenerate(bytes);
|
||||
// } else {
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.objectweb.asm.MethodAdapter;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.springsource.loaded.Constants;
|
||||
|
||||
|
||||
/**
|
||||
* This bytecode rewriter intercepts calls to generate made in the CGLIB framework and allows us to record what generator is called
|
||||
* to create the proxy for some type. The same generator can then be driven again if the type is reloaded.
|
||||
@@ -38,7 +37,8 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
|
||||
public static Map<Class<?>, Object[]> clazzToGeneratorStrategyAndClassGeneratorMap = new HashMap<Class<?>, Object[]>();
|
||||
public static Map<Class<?>, Object[]> clazzToGeneratorStrategyAndFastClassGeneratorMap = new HashMap<Class<?>, Object[]>();
|
||||
|
||||
public String prefix;
|
||||
|
||||
public static byte[] catchGenerate(byte[] bytesIn) {
|
||||
ClassReader cr = new ClassReader(bytesIn);
|
||||
CglibPluginCapturing ca = new CglibPluginCapturing();
|
||||
@@ -50,6 +50,16 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
private CglibPluginCapturing() {
|
||||
super(new ClassWriter(0)); // TODO review 0 here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
// The name could be a repackaged form of cglib:
|
||||
// net/sf/cglib/core/AbstractClassGenerator
|
||||
// org/springframework/cglib/core/AbstractClassGenerator
|
||||
int index = name.indexOf("/cglib");
|
||||
prefix = name.substring(0,index);
|
||||
super.visit(version,access,name,signature,superName,interfaces);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return ((ClassWriter) cv).toByteArray();
|
||||
@@ -64,7 +74,7 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
}
|
||||
}
|
||||
|
||||
static class CreateMethodInterceptor extends MethodAdapter implements Constants {
|
||||
class CreateMethodInterceptor extends MethodAdapter implements Constants {
|
||||
|
||||
public CreateMethodInterceptor(MethodVisitor mv) {
|
||||
super(mv);
|
||||
@@ -88,8 +98,8 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
// ALOAD 0
|
||||
// INVOKEINTERFACE net/sf/cglib/core/GeneratorStrategy.generate(Lnet/sf/cglib/core/ClassGenerator;)[B
|
||||
mv.visitVarInsn(ALOAD, 0); // AbstractClassGenerator instance
|
||||
mv.visitFieldInsn(GETFIELD, "net/sf/cglib/core/AbstractClassGenerator", "strategy",
|
||||
"Lnet/sf/cglib/core/GeneratorStrategy;");
|
||||
mv.visitFieldInsn(GETFIELD, prefix+"/cglib/core/AbstractClassGenerator", "strategy",
|
||||
"L"+prefix+"/cglib/core/GeneratorStrategy;");
|
||||
mv.visitVarInsn(ALOAD, 0); // AbstractClassGenerator instance
|
||||
mv.visitMethodInsn(INVOKESTATIC, "org/springsource/loaded/agent/CglibPluginCapturing", "record",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)V");//Lnet/sf/cglib/core/GeneratorStrategy;Lnet/sf/cglib/core/AbstractClassGenerator);");
|
||||
@@ -114,7 +124,7 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
// a is something like 'UndeclaredThrowableStrategy'
|
||||
// b is an Enhancer: namePrefix="example.Simple" superclass=example.Simple
|
||||
String generatorName = b.getClass().getName();
|
||||
if (generatorName.equals("net.sf.cglib.proxy.Enhancer")) {
|
||||
if (generatorName.endsWith(".cglib.proxy.Enhancer")) {
|
||||
try {
|
||||
Field f = b.getClass().getDeclaredField("superclass");
|
||||
f.setAccessible(true);
|
||||
@@ -124,7 +134,7 @@ public class CglibPluginCapturing extends ClassAdapter implements Constants {
|
||||
} catch (Throwable re) {
|
||||
re.printStackTrace();
|
||||
}
|
||||
} else if (generatorName.equals("net.sf.cglib.reflect.FastClass$Generator")) {
|
||||
} else if (generatorName.endsWith(".cglib.reflect.FastClass$Generator")) {
|
||||
try {
|
||||
Field f = b.getClass().getDeclaredField("type");
|
||||
f.setAccessible(true);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP
|
||||
removeClazzFromMethodResolverCache(clazz);
|
||||
clearCachedIntrospectionResults(clazz);
|
||||
reinvokeDetectHandlers(); // Spring 3.0
|
||||
reinvokeInitHandlerMethods(); // Spring 3.1
|
||||
reinvokeInitHandlerMethods(); // Spring 3.1
|
||||
}
|
||||
|
||||
private void removeClazzFromMethodResolverCache(Class<?> clazz) {
|
||||
@@ -211,6 +211,15 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP
|
||||
Method method_initHandlerMethods = clazz_AbstractHandlerMethodMapping.getDeclaredMethod("initHandlerMethods");
|
||||
method_initHandlerMethods.setAccessible(true);
|
||||
method_initHandlerMethods.invoke(o);
|
||||
} catch (NoSuchFieldException nsfe) {
|
||||
if (log.isLoggable(Level.WARNING)) {
|
||||
if (nsfe.getMessage().equals("handlerMethods")) {
|
||||
log.warning("problem resetting request mapping handlers - unable to find field 'handlerMethods' on type 'AbstractHandlerMethodMapping' - you probably are not on Spring 3.1");
|
||||
}
|
||||
else {
|
||||
log.warning("problem resetting request mapping handlers - NoSuchFieldException: "+nsfe.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user