Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bootstrap executable jar file in classpath when server starts

I have a a library that is bundled as an executable jar file and added to weblogic / tomcat classpath, how can I execute a main method from the jar file when the server is starting and loading the classes from the jar file.

what I want to is to have some initialization code to be executed first thing when the jar file is loaded and server is starting without any user intervention.

Note: I know I can bundle my jar in a war file, but I have some aspectj code in my library that I want to weave all running applications in the jvm, when I bundle my jar in war file, the aspectj code will only weave into the classes in the war file so I added my library jar file in the classpath.

Thanks in advance.

like image 904
Sammy Avatar asked May 31 '13 11:05

Sammy


People also ask

What is the correct way to run a JAR file providing the classpath of the main function?

To run an application in a nonexecutable JAR file, we have to use -cp option instead of -jar. We'll use the -cp option (short for classpath) to specify the JAR file that contains the class file we want to execute: java -cp jar-file-name main-class-name [args …]

How do I find the classpath of a JAR file?

To check our CLASSPATH on Windows we can open a command prompt and type echo %CLASSPATH%. To check it on a Mac you need to open a terminal and type echo $CLASSPATH.

How do I know if a jar is classpath?

forName("com. myclass") where com. myclass is a class that is inside (and only inside) your target jar; if that throws a ClassNotFoundException , then the jar is not on you current classpath. Bear in mind, though, that loading a jar at runtime is not very simple, you need to mess with classloaders.


2 Answers

Add a class inside your JAR with the following code:

public class TomcatStartupListener implements org.apache.catalina.LifecycleListener {
  public void lifecycleEvent(org.apache.catalina.LifecycleEvent event) {
    if (event.getType().equals("after_start")) {
      // call your main method here
    }
  }
}

Note: In order to compile this, you need to add <tomcat-dir>/lib/catalina.jar to your classpath. Otherwise when compiling it won't be able to find the necessary interfaces (org.apache.catalina.LifecycleListener and org.apache.catalina.LifecycleEvent). Once you're done with the compiling, put the JAR as usual under <tomcat-dir>/lib.

Now open <tomcat-dir>/conf/server.xml and add the following under the <Server> section:

<Listener className="com.yourpackage.TomcatStartupListener" />

Now whenever your Tomcat server starts, this TomcatStartupListener class inside your JAR will be called, and you can invoke your main method. There are a whole lot of other event types too! You can use any of these event types:

  • before_init
  • after_init
  • before_start
  • configure_start
  • start
  • after_start
  • before_stop
  • stop
  • configure_stop
  • after_stop
  • before_destroy
  • after_destroy

This approach is necessary because of the way the classloaders work in Tomcat (or even most JVMs). Here are the important points from that link:

There are three aspects of a class loader behavior
  Lazy Loading
  Class Caching
  Separate Namespaces

The JVM will get very heavy if all classes inside all JARs get loaded indiscriminately. So the classes inside shared JARs are loaded only on-demand. The only way for you to invoke the main method is to add the above lifecycle listener.

like image 98
Subhas Avatar answered Oct 24 '22 18:10

Subhas


Perhaps the simplest thing to do is to deploy a trivial servlet in a .war file that references your .jar file. The servlet can be configured to start up upon deployment/container start, and then it can invoke the class containing your main() method.

like image 23
Brian Agnew Avatar answered Oct 24 '22 17:10

Brian Agnew