Sammy
Sammy

Reputation: 4578

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.

Upvotes: 8

Views: 3229

Answers (4)

Badaro
Badaro

Reputation: 576

You need to register a Java Agent. See this link: java.lang.instrument.

java.lang.instrument provides services that allow Java programming language agents to instrument programs running on the JVM.

This is the right way to do this.

Upvotes: 0

Subhas
Subhas

Reputation: 14408

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.

Upvotes: 5

Olaf Kock
Olaf Kock

Reputation: 48057

As application servers / servlet containers typically have a lot of different classloaders, you'll most likely need a different strategy for weaving aspects into your code than in standalone applications.

I would recommend to add the aspects to every war file deployed at build time. This might be following a common technique - as opposed to a server specific one.

Further, I'm not sure it can actually be done (properly & supported) on a server. Typically a server is built to separate all webapps from each other. You might get it to work, but it might break on the next update of the server.

It might be easier to suggest an alternative technique if you'd state the problem that you want to solve with your proposed approach.

Edit after your comment: Consider the standard web application lifecycle: You can execute some code, e.g. in a servlet, upon it being deployed. If you insist on your code being contained in main, you can call this method from your webapp's initialization code.

Upvotes: 0

Brian Agnew
Brian Agnew

Reputation: 272217

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.

Upvotes: 2

Related Questions