如何为最终类创建动态代理? [英] How can I create dynamic proxy for final Class?

查看:122
本文介绍了如何为最终类创建动态代理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之:
1.我有一些最后的课,我想为它创建动态代理。我该怎么做?
2.我可以将MethodHandle转换为Method吗?

In short: 1. I have some final class that I want to create dynamic proxy for it. How can I do it? 2. Can I convert MethodHandle to Method?

详细信息
首先,是否存在任何要转换的API MethodHandle to Method?像java.lang.invoke.MethodHandles中的东西

Details First of all, does exists any API to convert MethodHandle to Method? Something like in java.lang.invoke.MethodHandles

public MethodHandle unreflect(Method m) throws IllegalAccessException;

但是方式相反?

假设我想创建动态java.lang.reflect.Method。它是不确定的

Let say I want to create dynamic java.lang.reflect.Method. It is defiend as

public final
   class Method extends AccessibleObject implements GenericDeclaration,
                                                 Member ;

因此,如果我想使用JDK动态代理,我必须使用一些接口(例如成员)。虽然有2个主要的抽屉。首先,方法如

So, if I want to use JDK Dynamic proxy I must use some interface (Member for example). There 2 main drawabacks though. First, method such as

public Class<?>[] getParameterTypes();

,例如

public Class<?> getReturnType();

不是任何界面的一部分,而是广泛使用。

are not part of any interface, while they are extensively used.

第二个缺点是它无法提供直接替换。也就是说,我无法将我的动态代理传递给期望java.lang.reflect.Method的代码。

The second drawback is that it fails to provide drop-in replacement. That is, I can't pass my dynamic proxy to the code that expects java.lang.reflect.Method.

另一种方法是使用CGLIB或Javaassist。 AFAIK,CGLIB不能代理最后一堂课,不是吗? Javaassist可以代理最终类吗?如何从班级中删除最终标识符? AFAIL,Javvassist可以某种方式做到......

Another approach is to use CGLIB or Javaassist. AFAIK, CGLIB can't proxy final class, does he? Can Javaassist proxy final class? How can I "remove" final identifier from the class? AFAIL, Javvassist can somehow do it...

推荐答案

这取决于你需要什么样的代理。基本上有三种方法可以实现这一目标,其中两种在生产代码中是可行的。正如@probrekely所说,cglib或javassist的问题在于它们动态地创建了一个子类,这是最终类不可能的。你可以通过以下方式避免这种情况:

It depends on what kind of proxy you need. There are basically three aproaches of how you can achieve this, of which two are feasible in production code. As @probrekely stated, the problem of cglib or javassist ist that they dynamically create a subclass what is not possible for final classes. You can avoid this by:


  • 禁用字节码验证。 Java运行时验证字节代码,以确保不加载恶意字节代码。例如,当通过网络或互联网接收课程(例如小程序)时,这很重要。这样,你可以创建一个final类的子类,因为字节码验证器不会阻止你。假设您可以在仅运行受信任的代码时禁用此验证。这可以通过运行来完成:

  • Disabling byte code verification. The Java run time verifies byte code in order to secure that no malicious byte code is loaded. This is important when for example receiving classes over the network or the internet, for example an applet. This way, you could create a subclass of a final class since the byte code verifier would not stop you. Hypothetically, you can disable this verification if you run trusted code only. This can be done by running:

java -Xverify:none ApplicationName

然而,这是我建议你最少的解决方案。我不会将此方法用于生产代码,但它肯定是最容易实现的解决方案。

This is however the solution I would recommend you the least. I would not use this aproach for production code but it is most certainly the easiest solution to implement.

删除 final 来自加载类的修饰符,在加载类之前或之后。这可以通过使用 Java代理来实现。可以通过命令行在应用程序启动时安装Java代理,也可以在运行时通过附加API 。使用像ASM这样的字节代码工具,您可以解析原始字节数组并从所有感兴趣的类中删除最终修饰符。也可以重新定义已加载的类。删除 final 修饰符不会引入与旧类版本的冲突,以便始终可以进行重新定义。

Remove the final modifier from loaded classes, either before or after the classes are loaded. This can be achieve by using a Java agent. A Java agent can be installed at application startup via the command line or at runtime via the Attach API. With a byte code tool like ASM, you could parse the original byte array and remove the final modifier from all classes of interest. It is also possible to redefine classes that were already loaded. Remove a final modifier does not introduce conflicts with old class versions such that such a redefinition is always possible.

执行与删除 final 修饰符相同的操作,但重新定义加载的类以实际包含原始类中的所有检测逻辑。这个问题最需要付出最大努力,但这将使您的仪器转换为所有其他代码。这将是所有解决方案中最干净的解决方案。

Do the same as I described with removing the final modifier but redefine the loaded class to actually contain all your instrumentation logic within the original class. This aporach will most certanly require the biggest effort but this will make your instrumentation transperent to all other code. This would be the cleanest solution of all solutions.

这篇关于如何为最终类创建动态代理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆