There must be a better way than the way I do it, but I tend to do this in a very manual way.
- Every Jar must have it's version number in the file name (if it doesn't change it's name).
- each application has it's own classpath.
- There must be a reason to start using an updated Jar (new version). Don't just change because it is available, change because it gives you functionality that you need.
- Each release must include all Jars that are needed.
- I keep a Version class that knows the list of Jars it needs (this is coded into the source file) and can be checked at runtime against the list of Jars in the classpath.
As I said, it is manual, but it works.