I have a web application and two class files,
First class is MyClass.class which is inside the abc.jar file (WEB-INF/lib/abc.jar) and
Second class is YourClass.class which is inside classes folder (WEB-INF/classes/ YourClass.class).
My question is which class would load first when the Application starts? And Why ?
In my experience you can't predict the order in which the classes are loaded by the JVM.
Once I made a test runner (kinda Maven's Surefire) and with the same JVM and OS it loaded classes in different order when run in different machines. The lesson learnt:
You shouldn't build your applications
to depend on class loading order
Classes are loaded as needed, for some definition of "needed". Exactly when a class is loaded is dependent upon the JRE implementation, javac implementation, exactly what thread are up to, server code and, of course, application code. It's a bad idea to make assumptions in this area. If you want to see what happens for a particular run, you can use -verbose:class
Sun's class loader docs always say WEB-INF/classes OR WEB-INF/lib, but doesn't say which one will be checked first.
From IBM docs:
"The rules for loading classes are spelled out in detail in the JVM specification. The basic principle is that classes are only loaded when needed (or at least appear to be loaded this way -- the JVM has some flexibility in the actual loading, but must maintain a fixed sequence of class initialization). Each class that gets loaded may have other classes that it depends on, so the loading process is recursive."
So I think the answer is: It depends on which classes is needed in your application first.
As duffymo points out, this can vary. One way you might ascertain the sequence for this specific app is to insert Response.Write text in the class constructors and web web app page loading methods. "Instantiated object in Class A", "Opened web page MyPage", and so on.
Once you've figured out the sequence, comment out the code for those so you can reuse them later to verify that you haven't made a change (such as instantiating an object earlier or later) that affected the sequence.
Related
I have a servlet which takes in some parameters. One of the parameters include the class name which should do some operations based on the other parameters sent to the servlet. The class name parameter is dynamic so the servlet wouldn't know which class to load beforehand.
Since the classes change frequently (for maintenance) i need to keep the classes outside of the Application since I cannot restart server in the production environment.
Also I need to keep in mind if the classes change the servlet needs to load up the most recent version of the class.What is the best option that i have.
Use a rule engine.
Use dynamic class loading but I am scared that after some there will be simply too many classes loaded in the memory and permgen space will suffer.
Please advise. Thanks in advance
This sounds like potentially dangerous in terms of security, but I am assuming you have taken steps to mitigate already.
The most straight-forward way, I believe, is to use dynamic class loading. Construct a URL classloader to load off a fixed file system location (make sure people cannot arbitrarily run any class they want!) load the class using that and execute the code (possibly via reflection as the class will not be visible on your web application's classloader) and properly dispose of the classloader and any objects created (such that there are no memory leak) As you mentioned, you might need to increase PermGen, but that goes for any solution that involves loading additional classes (which is part of your requirement)
I'm working on a sandbox feature for my java antivirus, and I've come into a question: Does the specified package on a class matter for compilation?
Example:
I'm running a program that wants to use Runtime.getRuntime().exec(), when the classloader attempts to load that to run a method, does it check the package qualified in the file, if they exist? I would prefer not to try and change files in the JVM, but to simply load ones from a different package. I can accomplish the loading and such, but my only dilemma, will it crash and burn? Inside the java, it would be registered as say, java.lang.Runtime, but the compiled code will say for example pkg.pkg.Runtime and will it need to extend the old runtime? My guess is that extending the old runtime would just break it. Does anyone know anything about this? I'm working on making a testable example, but I'm still a bit away and wanted to get some answers, as well as this might benefit some people.
Does the specified package on a class matter for compilation?
Yes it does matter. A class called pkg.pkg.Runtime() cannot be loaded as if it was java.lang.Runtime.
Furthermore, if my memory is correct, the JVM has some additional security measures in it to prevent normal applications from injecting classes into core packages such as java.lang.
If you need to change the behaviour of the java.lang.Runtime class (for experimental purposes!) then I think you will need to put your modified version on the boot classpath, ahead of the "rt.jar" file.
However:
This level of tinkering can easily result in JVM instability; i.e. hard JVM crashes that are difficult to diagnose.
If your aim is to produce a "production quality" tool, then you will find that things that involve tinkering with the JVM are not considered acceptable. People are going to be very suspicious of installation instructions that say things like "add this to your installed JVM's bootclasspath".
Distributing a "tinkered with" JVM may fall foul of Oracle's Java licensing agreement.
My advice would be to look for a less intrusive way of doing what you are trying to do. For instance, if you are trying to do virus checking, either do it outside of the JVM, or in a custom application classloader.
You commented:
I have a custom classloader, my question is: If I compile a class that is labelled as say, pkg.pkg.Runtime, can I register in my classloader as java.lang.Runtime?
As I said above, no you can't. A bytecode file has the classname embedded in it. If you attempt to "pull a swifty" by loading a class with a different name, the JVM will throw an Error.
And:
If not, then how can I replace the class? If the compiled package name has to equal the request referenced naming, then can I modify the .class file to to match, or perhaps compile it as if it were in the java.lang package?
That's what you would have to do. You need to name the class java.lang.Runtime in the source code and compile it as such.
But what I meant by my advice above is that you should use do the virus checking in the class loader. Forget about trying to replace / modify the behaviour of Runtime. It is a bad idea for the reasons I listed above.
The situation at hand is not as simple as the title seems to indicate.
Java 1.6_17 running via JWS.
I have a class, lets say MyClass and one of its instance member variables is a Type from an errant 3rd party library where during class initialization it dynamically tries loading some of its own classes with Class.forName(String). In one of these cases it happens to dynamically call: Class.forName("foo/Bar").This class name doesn't follow the JLS for binary names and ultimately leads to a java.lang.NoClassDefFoundError: foo/Bar.
We have a custom ClassLoader which I've added a sanitize method to ClassLoader.findClass(String) and ClassLoader.loadClass(String) which fixes this problem.
I can call stuff like:
myCustomClassLoader.findClass("foo/Bar")
Which then loads the class without any problems. But even if I load the class ahead of time, I still get the exception later. This is because during initialization of MyClass which refers to Bar - their code ends up calling Class.forName("foo/Bar") in a static block somewhere. This actually would be OK if the ClassLoader it was trying to use was my custom class loader. But it isn't. It is the com.sun.jnlp.JNLPClassLoader which doesn't do such sanitation, thus my problem.
I've made sure that Thread.currentThread().getContextClassLoader() is set to my custom class loader. But this (as you know) has no effect. I even set it as the first thing i do in main() due to some stuff I read and still, MyClass.class.getClassLoader() - is the JNLPClassLoader. If I could force it to NOT be the JNLPClassLoader and to use mine instead, problem solved.
How can I control which ClassLoader is used to load the class via their static Class.forName("foo/Bar") call made during class initialization? I believe if I can force MyClass.class.getClassLoader() to return my custom class loader, my problem will be resolved.
I'm open to other options if anyone has ideas.
TL;DR: Help me force all Class.forName(String) calls in a third party library which are referenced by MyClass - to use the classloader of my choosing.
This reminds me of an article I read 10 years ago about the classloading arrangements in Java. It's still there on JavaWorld.
The article won't answer your question directly, but it may help understand your problem. You need to cause MyClass to be loaded through your custom class loader and trump the default class loading behavior, which is to first delegate class loading to the parent classloader and only attempt to load a class if that fails.
Allowing MyClass to get loaded by a classloader other than yours will store a relationship from the instantiated class to that classloader (via getClassLoader) and cause Java to use that other classloader to try to discover any referenced classes found at compile time, effectively bypassing your custom class loader by virtue of the class loader hierarchy and the delegation model. If MyClass is instead defined by your class loader, you get a second chance.
It sounds like a job for something like URLClassLoader, overriding loadClass and trumping the delegation model for classes residing in your JARs. You'll probably want to use a bootstrap approach (as suggested by Thomas in a comment above) to force a single entrypoint class to be loaded through your custom class loader, dragging all the others with it.
Also informative is this other JavaWorld article by the same guy, which warns you about the caveats of Class.forName. That too may trip your classloading arrangements.
I hope this helps and proves informative. In any case, it sounds like a difficult solution that is easy to break as your code evolves.
I think everyone gave good solid attempts at answering the problem. However, it turns out that I misdiagnosed the problem.
I had a coworker take over the problem and asked him to get a JDK with debug flags on so we could debug the JNLPClassLoader to see what was going on as I had tried all of the suggestions here + some.
We ended up getting OpenJDK because recompiling the JDK from scratch is a total nightmare (we tried). After getting OpenJDK working with our product and debugging through the JNLPClassLoader - it turns out that it was still using a REALLY old .jnlp from months earlier that had the resource path wrong and thus why it couldn't find the class.
We were confused why it was still using the ancient .jnlp even though we had redeployed the server correctly many times with the correct .jnlp and lots of code changes between which were reflected in our client application when run.
Well, it turns out that on client machines, Java caches the .jnlp file. Even if your application changes and it redownloads your application, it still won't re-download the new .jnlp for whatever reason. So it will use all of the new code, but look up resources/class paths using the cached .jnlp.
If you run:
javaws -uninstall
On the client machine then that will clear the .jnlp cache and next time it will use the correct .jnlp file.
Really sad that this was the problem. Hopefully, this saves someone else endless hours of frustration like it caused us.
If you run out of ideas with patching the ClassLoaders themselves, you might consider rewriting the library bytecode itself -- just replace the "foo/bar" constant with the correct value, and then you don't need to customize further class loading at all!
You could do this either at runtime or beforehand.
This may, and should be, a question that has been asked and answered many times over, but I just cant find the answer.
If I have a compiled application running on a server, can I compile the application on my local machine, and swap a class that I compiled on my local machine, with the one on the server?
In other words, can I replace a file that has been compiled and is on the server side, with a file almost identical that has been compiled, and is located, on my local machine?
Since the version on the server side has some hard-coded connections in other files, and I dont know all of the places, I would prefer to only swap the one file that I need, instead of doing a recompile for the application as a whole.
The answer to your question is yes, you can replace a class file, but it is somewhat complicated in that you have to be sure that no other dependencies have changed.
For example, if the class you are compiling involved changing method signatures of methods that are used in other classes, you will need to replace those as well. As long as the method signatures of public, protected, or default methods aren't changed, you should be okay.
As a side-note, if this is something you do often, you'll quickly realize why objects are often passed into methods instead of individual parameters.
public MyObject getObject(MyObject2 mySecondObject)
vs
public MyObject getObject(int a, int b, int c)
When you need to add a new property to an object passed into a method, the method signatures don't change, but when you add or remove a parameter on the method signature itself, it creates a chain reaction on all dependencies, requiring that you compile and replace those class files as well.
As a final point to highlight, it's worth noting that changes you make to private methods or private variables, or even the definitions of a method, have no bearing or impact on other class files. The only thing that matters is that you uphold the contract that your methods have with other classes in that the inputs and outputs always take and return the same data types.
This highlights the importance of encapsulation of instance variables and how those dependencies are hidden from other classes.
Yes, you can do it. Moreover due to hot spot the class will be even reloaded at runtime, so you do not have to restart the server. This is very useful during development cycle.
But be careful replacing one separate class. If the class has references to other classes changed in your environment the replacement will fail on server.
I assume you're talking about an 'offline' substitution (I mean you can restart the server).
In this case the following solution can be viable:
Java uses classpath variable. There you define series of jars/folders where your process will look for files.
So you can do the following:
Create your new class (it should be with the same name and reside in the same package) and compile.
Create on server the folder where you're planning to store your updated class.
Update the classpath variable (probably in the startup script of your application) so that this folder will appear before the rest of your classes.
Restart your server. Now your new class will be resolved before the old one and loaded.
Caution:
This works for 'standalone' applications and in general for those that don't fiddle with custom class loaders (for example this is the case in application servers).
More complex solution can be based on define your class loader that will take a look on such a folder (as I've described) and try to load resources from there.
Hope this helps.
I'm using JDK 1.6 to run a small application. However I set a very massive classpath which includes a lot of classes.
When I run the application will all classes in the classloader been loaded even if they're not actually used in my application? If not, how to force the classloader do so, and if yes, how to avoid it? Thanks!
E.g.,I'm using ant 1.7 to run my application.
Best Regards,
Robert Ji
No, The ClassLoader loads the class when the class is needed in memory. It doesn't load all classes at once as it can run out of memory.
They are loaded when needed. But what "when needed" means, might depend on the classloader. Typically, when a class is loaded it also checks the existence of all classes it references - and it might also load them.
You can check it by adding the option -verbose to your Java JVM, it outputs then all the classes it loads, and from where.
To my knowledge it's impossible to load all classes if they are not accessed explicitly. Class in only loaded when it's constructor or any other static member is first accessed, this rule applies to nested classes as well.