I know this isn't "best practice", but can I include all of the dependencies in one big jar?
问题:
回答1:
There's a utility called One-Jar which does what you want, although I'd advise against it. The performance is usually awful.
回答2:
My feeling is that calling One-Jar's performance awful and poor is unjust. For moderately sized application one can expect startup will take a couple of seconds longer (which does not affect JVM splash screen though). Memory overhead of tens of megabytes is negligible for most environments, except perhaps embedded systems. Also, One-Jar is capable of automatically extracting some files to the file system, which saves the need to develop an installer in my case.
Below is an attempt to quantify the performance impact introduced by One-Jar to my application. It is Swing-based GUI application, consists of 352 classes obfuscated with ProGuard 4.5b2. One-Jar 0.96 is used to bundle resulting classes with 12MB worth of libraries (ODFDOM, Saxon HE, Xerces, Jaxen, VLDocking, Apache Commons, etc). I have compared performance of the obfuscated jar with the same jar processed by One-Jar.
- From JVM start to the start of of main() method: 0.5s without One-Jar and 1.7s with One-Jar. From JVM start to the appearance of application window on the screen: 2.3s without One-Jar and 3.4s with One-Jar. So One-Jar adds 1.1s to startup time.
- One-Jar will not increase the delay between JVM start and splash image appearing on the screen (if implemented via jar manifest), so the startup time increase is not too annoying for interactive applications.
- We are talking about a class loader, so there should be no impact on code execution speed, unless you are extensively using dynamic class loading.
- Looking at JVM statistics (via jconsole) shows that One-Jar'red version takes more heap memory. For my application the overhead is in the order of tens of MBs. I saw figures like 16MB vs 40MB, 306MB vs 346MB, 131MB vs 138MB, depending on now much user data the application is handling and now long time ago garbage collector has been executed.
The above timing was obtained by taking a timestamp just before starting JVM from Linux shell, in beginning of main() method, and in windowOpened() event handler of my application window. The measurements were taken on a not particularly fast D820 laptop, with dual core 1GHz CPU and 2G or RAM running Ubuntu 8.04.
Hope it helps.
回答3:
I used maven assembly plugin with jar-with-dependencies descriptor
回答4:
Using the good old Ant: just use zipgroupfileset
with the Ant Zip task
<zip destfile="out.jar">
<zipgroupfileset dir="lib" includes="*.jar"/>
</zip>
This will flatten all included jar libraries' content.
回答5:
One-JAR loads all the dependency jars into memory on startup. This may sound horribly inefficient, but nobody has complained to me about it since it was released in 2004. The likely effect of pre-loading is an overall speed up of classloading for the application, since the classloader does not have to repeatedly scan the classpath for resources and classes as the application runs: everything is hashmapped.
It's pretty simple to build a lazy loader which would load on-demand: but I'm of the school that says "build-it, measure-it, improve-it if necessary" and so far there has been no need to improve it.
I will keep this in mind for future releases (or if someone else wants to tackle it, that would be great too, since without a very large application to measure against, it's hard to know if changes are improvements).
回答6:
If you want to do this there is a tool called Jar Jar Links which will do this for you. Never used it but it is hard to forget the name.
回答7:
You can unjar files and repack them using the command line
You can use [uberjar]
You can use fatjar
回答8:
Often you can, but sometimes there are unusual legal or technical reasons not to.
Legal: For example, we discovered that at the time we wanted to, we could not bundle the JavaMail jar files together into one big package with the rest of our app, but the license agreement said we had to keep them separate.
Technical: Another problem might be custom class loaders look for specific resources or classes inside of specific jar files. This often happens in the context of containers for application servers or ESBs.
How: To do it, just unjar everything into one directory, and then rebuild a jar from there. You might have to tweak some settings in the META-INF folder to remove the requests to load the additional jars, and to handle the case where different jars each have a default class to run. There are some third-party utilities which might help, but unless you know what they are doing, you'd want to be careful.
回答9:
Eclipse 3.4 and up allows you to do this. Right click your project, select Extract, and navigate to the Runnable Jar option. Select Next. Choose the appropriate settings and your off and running. Also I seem to recall that this functionality is achieved using the same or similar libraries that FatJar (mentioned above) uses.
回答10:
Just for completeness, ProGuard will do this for you, as well as optionally obfuscating and shrinking JARs. The latter function is especially useful for creating final deployment JARs.
回答11:
Also remember that .jar files are .zip files under the covers. You can use your favorite zip tools to (re)package them. In this case, you would have to deal with the manifest file yourself.