当JVM启动时,如何在Java中运行初始化方法?

3
我正在构建几个Java、Maven项目的Java库。由于这是一个库,因此任何项目中都没有main方法。在Web应用程序中,您可以创建一个实现ServletContextListener的类,它将在服务器启动时执行(例如,当Tomcat启动时)。我想对库做同样的事情(它既不是Web应用程序也不是控制台应用程序,只是一个可重用的库)。如果有人编写使用我的库的程序,我希望我的初始化器类在JVM启动时执行一些我希望它执行的初始化工作。我该怎么办呢?谢谢。

通常情况下,您只需将库添加到任何Java项目中,并导入您想要使用的类。如果您希望执行初始化程序类,则在其他Java程序的主方法中调用它。 - Nesan Mano
2
你的初始化程序是否必须在JVM启动时运行,或者只需要在任何库代码被使用之前运行?第一种情况需要向主代码添加代码来实现。第二种情况很常见,称为惰性初始化,即将初始化推迟到需要时再进行。 - Andreas
什么样的初始化?根据情况,可能只需在依赖于该初始化的类中放置“静态”块。或者可能需要通过文档向未来用户传达,在使用库之前需要进行一些预配置。这真的取决于我们所讨论的初始化类型。 - mypetlion
2
这听起来有点像 X-Y 问题,而且也不是库应该做的事情。 - Mick Mnemonic
1
@DimitriosEfthymiou 然后看一下我之前给出的链接,或者在网上搜索“惰性初始化”。如果你需要在使用配置注册表之前从属性文件中初始化它,那么它应该是在第一次访问时自动惰性初始化的注册表,例如在一个static初始化块中。 - Andreas
显示剩余4条评论
3个回答

3
如果您在命令行上添加一个JAR作为-javaagent:,则会在运行的程序的主方法之前调用premain方法。
例如:
import java.lang.instrument.Instrumentation;

public class Agent {
  public static void premain(String args, Instrumentation instrumentation){
    // early initalization
  }
}

https://zeroturnaround.com/rebellabs/how-to-inspect-classes-in-your-jvm/


1
您希望在使用(Java)库之前始终执行特定的初始化代码。已经提到了使用J2EE/Spring选项中的@PostConstruct。在使用Java SE时,您可以通过一个单例类来封装您的Java库 - 这是一个作为进入库其余功能的“入口”的类。单例类的构造函数可以调用所有必要的初始化代码,然后将控制权交回给调用者(主Web应用程序)。
public class LibraryInstance {

    private FunctionalClass1 functionalClass1;
    private FunctionalClass2 functionalClass2;
    ...

    private LibraryInstance() { runInitializingCode(); }
    private static final LibraryInstance instance = new LibraryInstance();
    public static LibraryInstance getInstance() {
        return instance;
    }

    private void runInitializingCode() { 
        ....
    }
}

应该开箱即用。

因此,您的建议是为每个项目创建一个API网关或门面。我想使用初始化代码,以便在JVM完成启动/初始化之前,在非常开始时将属性从prop文件注册到配置注册表中。那么,问题是当JVM启动时如何注册来自src/main/resources的prop文件中的props? - Dimitrios Efthymiou
您可以在主Web应用程序中添加一个@PostConstruct注释的方法。该方法可以读取您提到的属性,随后调用LibraryInstance(可能会传递相关的参数子集 - 在我上面的代码示例中未显示),以便在JVM启动期间实例化库。 - Flying Dutchman

1
我想问题的关键在于如何在使用对象之前初始化它们。这取决于您需要哪些数据来执行初始化。如果您需要:
- 执行不依赖外部信息的初始化工作,则可以在对象创建时(例如在构造函数中或者如果您使用EE框架,则在类似于@PostConstruct注释的方法中)或在静态初始化块中进行此操作,该块将在类加载时运行。 - 从用户环境中获取数据,可以使用System类中的静态调用提供此功能。同样,这可以在对象构建时完成。 - 用户已经对如何使用您的库做出了静态选择,请考虑使用属性文件(需要记录文档)。同样,对象构建是执行此操作的时间。 - 用户已经对使用您的库做出了动态选择,则会在与您的库协作的对象的某个地方在运行时可用。
如果您的初始化工作需要大量资源,并且您希望在用户应用程序启动时执行它,则我认为实现此操作的最佳方式是记录要求并要求用户调用特定方法以执行初始化。
从图书馆用户的角度来看,我想知道您的图书馆何时进行初始化工作以及该工作的复杂程度。我不希望图书馆决定何时消耗资源,特别是在启动时,当我可能有很多自己的启动代码、框架代码和无数其他初始化部分都导致启动延迟时。 编辑: 只是为了明确,所有这些选项都是在应用程序级别上。JVM本身已经启动运行。我们谈论的是应用程序代码的初始化,而不是JVM。

我没有使用Spring Beans。静态块是完美的选择,但不幸的是它会在第一次使用类时执行(lazy-init),而不是在类加载器在JVM启动时工作时执行。我想使用初始化代码,以便我可以在JVM完成启动/初始化之前,在最开始的时候将一些属性从prop文件注册到配置注册表中,即在任何人调用库之前。所以,问题是当JVM启动时如何注册来自prop文件的props(这些文件存在于src/main/resources中)? - Dimitrios Efthymiou
静态块会在类加载时初始化,而不是用户首次访问类方法时,因此这可能是一个不错的选择。除此之外,如果您要求用户编辑属性文件,则对我来说也有意义要求他们调用初始化方法以使用您的库。 - slowbug
我仍然不理解“在JVM完成启动/初始化之前”的那一部分。在没有先执行static块的情况下,无法调用类上的方法,无论是静态的还是非静态的。你正在关注执行的确切点,但对我来说这毫无意义。 - SeverityOne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接