什么时候加载 Java 类? [英] When is a Java Class loaded?

查看:19
本文介绍了什么时候加载 Java 类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在网上搜索了几个小时,没有得出任何结论.

I searched the internet for more than couple of hours and could not reach any conclusion.

最近我决定将 BouncyCastle 用于 SSL,但我希望它默认关闭,因此 BouncyCastle jar 可能不在类路径中.

Recently I decided to use BouncyCastle for SSL but I wanted it to off by default, so that BouncyCastle jar may not be in the class path.

private void enableBouncyCastleForSSL() {
   if (config.isBouncyCastleEnabled()) {
        Security.insertProviderAt(new BouncyCastleProvider(), 1);
    }
} 

即使配置被禁用,它也在寻找 BouncyCastle 并且它因类加载器错误而失败.java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider

Even when config is disabled, it was looking for BouncyCastle and it failed with class loader error. java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProvider

我尝试只移动一行 Security.insertProviderAt(new BouncyCastleProvider(), 1);一种新方法,它表现出同样的问题.

I tried moving just the line Security.insertProviderAt(new BouncyCastleProvider(), 1); to a new method it exhibited the same problem.

但是当我引入一个类并将 BouncyCastle 移动到其中时,当配置被禁用时,类加载器问题不会出现

But when I introduce a class and move the BouncyCastle inside it, when the config is disabled, class loader issue does not appear

private void setupSSLProvider() {
    if (voldemortConfig.isBouncyCastleEnabled()) {
        SetupSSLProvider.useBouncyCastle();
    }
}
public class SetupSSLProvider {
  public static void useBouncyCastle() {
    Security.insertProviderAt(new BouncyCastleProvider(), 1);
  }
}

有些文章声称 Class 只有在第一次使用时才会加载.http://www.programcreek.com/2013/01/when-and-how-a-java-class-is-loaded-and-initialized/

Some articles claim that Class is loaded only when it is first used. http://www.programcreek.com/2013/01/when-and-how-a-java-class-is-loaded-and-initialized/

显然就我而言,Java8 加载了类中引用的类.

Apparently in my case, Java8 loads the class referenced in a class.

所以我的理解是 Java 会在执行类中的第一行代码之前加载一层深的类.是吗?

So my understanding is Java will load the classes one level deep, before executing first line of code in a class. Is that right ?

推荐答案

这个问题没有简单的答案.规范为不同的实现策略留下了空间,即使在一个实现中,它也取决于如何使用该类.此外,您的问题更多是关于什么时候会失败",这取决于它为什么会失败,例如一个类可能会在某个时间点加载以验证它的存在,但在稍后实际第一次使用时初始化.在这两个时间点,操作都可能失败,导​​致 NoClassDefFoundError.

There is no simple answer to this question. The specification leaves room for different implementation strategies and even within one implementation, it will depend on how the class is been used. Further, your question is more about "when can it fail" which depends on why it may fail, e.g. a class may be loaded at one point of time to verify its existence but initialized at a later time when it is actually first‑time used. At both points of time, the operation may fail causing a NoClassDefFoundError.

我们可以将引用的类分为三组:

We may categorize referenced classes into three groups:

  • 必须在链接时解析的类(例如超类)
  • 必须在验证时加载的类
  • 加载可以推迟到第一次实际使用的类

在您的情况下,BouncyCastleProvider 必须在验证时间加载,而不是第一次实际使用,因为您正在传递 new BouncyCastleProvider() 的结果 作为方法 Security.insertProviderAt(…) 的参数,并且验证者必须检查该类是否实际扩展了该方法的形参要求的 Provider 类型.

In your case, BouncyCastleProvider must be loaded at verification time, rather than its first actual use, because you are passing the result of new BouncyCastleProvider() as argument to the method Security.insertProviderAt(…) and the verifier must check whether the class actually extends the Provider type which the method’s formal parameter mandates.

何时进行验证,也是特定于实现的,因为至少允许以下可能性:

When verification will happen, is also implementation specific as at least the following possibilities are allowed:

  • 急切地遍历所有引用的类
  • 关于包含类的加载或第一次使用
  • 关于包含方法的第一次使用
  • 就在执行违规指令之前

Oracle 的 JVM 更喜欢方法的第一次使用,阅读:在方法入口处验证它,因此,将调用移动到另一个不会被执行的方法中,无论是否在另一个类中,对您来说就足够了.

Oracle’s JVM prefers a method’s first use, read: verify it at the method entry, thus, moving the invocation into another method that won’t get executed, be it in another class or not, is sufficient in your case.

但是为了与其他 JVM 兼容,将其移入另一个类更安全,但是为了遵守所有可能的 JVM,您甚至需要通过反射加载另一个类以避免直接引用可以通过一个急切的实现来遍历(或者首先通过 Class.forName("... .BouncyCastleProvider").newInstance() 反射性地实例化 BouncyCastleProvider).

But to be compatible with other JVMs, moving it into another class is safer, but to comply to all possible JVMs, you need to even load this other class via Reflection to avoid a direct reference that can be traversed by an eager implementation (or instantiate BouncyCastleProvider reflectively via Class.forName("… .BouncyCastleProvider").newInstance() in the first place).

这篇关于什么时候加载 Java 类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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