The first important thing (besides knowing how to set the classpath) is the hierarchy of the different classloaders.
You can always write your own classloader to append at the bottom of this hierarchy. Most servlet containers also provide their own classloader so look closely at the given documentation. For example this link points towards the classloader hierarchy of tomcat.
The loading of a class consists of 3 phases. This is described in the java specification:
To actually see this you can always execute some code with the verbose option of the jvm turned on:
java -verbose YourMainClassThis will log the class found and those phases. If you even want more information you can also try
java -verbose:class YourMainClass
The most common errors on this issue will be ClassNotFoundException and ClassCastException. Which you probably met before.
Another problem to be aware of is that each class (given the same package etc) can only be loaded once into the classloader. So if you provide an old version of your library on the extensions library of your jvm and add an updated version to your system classpath you will experience dependency conflicts. Only the old version will be loaded into memory because it's first in the classloader hierarchy. And if that old version is missing a method (or has another method signature) you'll get a NoSuchMethodException.
The next error can occur when a class is using native system libraries. When this library is not found the code will throw an UnsatisfiedLinkError. After this error occured the class will be obscured from memory so next calls on this class will give a NoClassDefFoundError. Which makes it tricky.
Other resources can be loaded from your classpath using ClassLoader.getResourceAsStream(String path)
internals of java classloading
demystifying classloading problems