Java 带有lambda的热交换代码失败,表明无法删除该方法 问题
热交换lambda失败 过程 我尝试热交换包含lambda的方法体 1.热交换代码 例外情况 3.思想 我知道在编译字节码时,仪器无法更改(添加、删除、修改)方法。 为什么我可以随意修改静态方法,但不能修改实例方法?您被绊倒了。根据bug报告,尽管规范继续声明不支持,但围绕Java 6所做的更改使实现接受有关添加或删除Java 带有lambda的热交换代码失败,表明无法删除该方法 问题,java,lambda,bytecode,hotswap,Java,Lambda,Bytecode,Hotswap,热交换lambda失败 过程 我尝试热交换包含lambda的方法体 1.热交换代码 例外情况 3.思想 我知道在编译字节码时,仪器无法更改(添加、删除、修改)方法。 为什么我可以随意修改静态方法,但不能修改实例方法?您被绊倒了。根据bug报告,尽管规范继续声明不支持,但围绕Java 6所做的更改使实现接受有关添加或删除私有静态和私有最终方法的更改 因此,当一个lambda表达式被分解成一个私有静态方法,该方法适用于所有未捕获此的lambda表达式时,更改它们就起作用了 对于捕获此的lambda表
私有静态
和私有最终
方法的更改
因此,当一个lambda表达式被分解成一个私有静态
方法,该方法适用于所有未捕获此
的lambda表达式时,更改它们就起作用了
对于捕获此的lambda表达式,其行为取决于编译器。在没有final
修饰符的情况下,将它们分解为private
实例方法已变得很常见,因此,它们不受所报告行为的影响。但原则上,编译器可以添加冗余的final
修饰符。还可以将这种lambda表达式的主体转换为静态
方法,接受此
引用作为参数。这种情况发生在较旧的编译器上
根据报告的修复是不考虑“这些限制可以在未来版本中解除”的说明书的声明,而是删除特征以符合规范的字面意思。将有一个选项,
-XX:{+|-}allowreDefinitiontoAddOrderDeleteMethods
在一段时间内切换从JDK 13开始的行为。作为旁注,您应该使用简化代理代码。除此之外,您是否了解lambda表达式是如何编译的(确切的结果是特定于编译器的)?这样,打印实际的“除糖后的方法”会很有用,它确定是否可能进行更改(这使问题完全独立于lambda表达式)。另一点需要理解的是,一旦添加了ClassFileTransformer
,该转换器将保持注册状态。在下一次重新传输FormClasses
调用后,它不会被删除。因此,在循环中使用相同的转换器实现调用addTransformer
是没有意义的,您必须知道,当您加载另一个代理时,这些转换器仍然存在。非常抱歉,我无法修改,,并且它不是一个循环。这只是为了方便启动后变得热起来,然后在代理代码中退出,您有一个循环,for(Class clazz:classes){…
并为每个匹配的类安装相同的转换器,尽管一个转换器已经足够了。除此之外,为什么你不能修改你的问题?点击链接。但是你没有回答重要的问题,你知道lambda体被编译成合成方法,只有那些方法才重要吗?在其他方面呃,换句话说,lambda表达式是完全不相关的,通常声明的方法的行为也是一样的。在给我一个链接之前不要允许修改,也许这是缺乏威望
public class Example {
private int x;
public void print (int y) {
Consumer<Integer> consumer = (key) -> System.out.println(key);
}
}
//Methods after sugar removal
First use code 1 to compile a class and put it in the directory, then run code 2 hot change
//from static to instance method failed
1、Consumer<Integer> consumer = (key) -> System.out.println(key);
2、Consumer<Integer> hot = (key) -> System.out.println(key + "" + this);
//After desugar method
private static synthetic lambda$print$0(Ljava/lang/Integer;)V
private synthetic lambda$print$1(Ljava/lang/Integer;)V
//change static method params count successful
String str = "args";
Consumer<Integer> methodCount1 = (key) -> System.out.println(key);
Consumer<Integer> methodCount2 = (key) -> System.out.println(key + str);
private static synthetic lambda$print$2(Ljava/lang/Integer;)V
private static synthetic lambda$print$3(Ljava/lang/String;Ljava/lang/Integer;)V
//change instance method params count failed
Consumer<Integer> instanceCount2 = (key) -> System.out.println(key + "" + this);
Consumer<Integer> instanceCount3 = (key) -> System.out.println(key + str + this);
private synthetic lambda$print$4(Ljava/lang/Integer;)V
private synthetic lambda$print$5(Ljava/lang/String;Ljava/lang/Integer;)V
//from nothing add or delete lambd successful (compile static method)
//from nothing add or delete lambd fail (compile instance method)
Consumer<Integer> instaceMethod = (key) -> System.out.println(this);
private synthetic lambda$print$6(Ljava/lang/Integer;)V
hot.accept(1);
consumer.accept(1);
public class JavaAgent {
public static void agentmain(String agentArgs, Instrumentation inst) throws Exception {
System.out.println("开始热更新");
// 获得所有已被装载的class文件
Class[] classes = inst.getAllLoadedClasses();
for (Class clazz : classes) {
if (clazz.getName().equalsIgnoreCase(agentArgs) || clazz.getName().equalsIgnoreCase("com.jason.Normal")) {
System.out.println(clazz.getName());
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
//System.out.println("hotswap class name :" + className);
String str = "";
if (className.contains("Example")){
str = "Example.class";
}else if (className.contains("Norm")){
str = "Normal.class";
}else {
return null;
}
byte[] bytes = fileToBytes(new File("C:\\hot\\"+str));
return bytes;
}
}, true);
// 重转换
inst.retransformClasses(clazz);
}
}
System.out.println("热更新结束");
}
public static byte[] fileToBytes(File file) {
try {
FileInputStream in = new FileInputStream(file);
byte[] bytes = new byte[in.available()];
in.read(bytes);
in.close();
return bytes;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public class HotSwap {
public static void hot(){
try {
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : list) {
VirtualMachine virtualMachine = null;
virtualMachine = VirtualMachine.attach(vmd.id());
// 获得代理类位置 + 传递参数
virtualMachine.loadAgent("C:\\Users\\DELL\\Downloads\\JavaHotSwap-master\\JavaAgent\\target\\agentmain.jar", "com.jason.Example");
virtualMachine.detach();
}
} catch (AttachNotSupportedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (AgentLoadException e) {
e.printStackTrace();
} catch (AgentInitializationException e) {
e.printStackTrace();
}
}
}
int i = new Random().nextInt();
new Example().print(i);
// Normal.show();
// System.out.println("hot");
HotSwap.hot();
new Example().print(i);
// Normal.show();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at com.jason.JavaAgent.agentmain(JavaAgent.java:60)
... 6 more
com.sun.tools.attach.AgentInitializationException: Agent JAR loaded but agent failed to initialize
at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:121)
at com.jason.HotSwap.hot(HotSwap.java:23)
at com.jason.Main.main(Main.java:33)
Agent failed to start!
Exception in thread "Attach Listener"