Spring multiple application contexts vs single application context in an ear - java

I have inherited an app which is packaged as ear file that has inside
- ear :
-APP-INF/lib (persitence.jar - hibernate+spring ... etc)
-war (web-services)
-jar (mdb)
-jar (mdb)
As I studied the app noticed that each module has inside the jar creates it's own Spring application context that is loaded on runtime.
It works ok but it would not be better to have only one application context ?
I wonder what are the benefits and drawback which this structure compared to the one where it is only an single application context used ?
To be more clear on runtime there are 3 application context roots loaded.It is not only that there are more application context files
Thanks

first of all: are you sure it isn't the same application context everywhere ? have you tested this ?
if they are all seperate:
the advantage is that those application contexts are shielded from eachother, which you could call loose coupling, which is a good thing; one can't influence the other, it keeps things clearer for the programmer.
the disadvantage is, it might be harder to access one application context from the other, but you can always find a way around this.

If the application very large then the application context of different modules is easy to manage and it doesn't create any overhead. At the time when application is up all the context xml files will be combined.
And I will also prefer to maintain separate application context files for separate set of configurations eg. security, datasource, aop etc. should be placed in separate context files.
When the application is small then you can go for single application context file for whole application. Otherwise different application context for different modules is easy to manage in case when you need to do some changes in any one of them. If you combine all of them then it will be very difficult to do any changes in that.
Hope this helps you. Cheers.

Few points against single application-context file that I can think of:
One file will get huge and it will be maintenance nightmare.
Developers of each component will modify,update same file can lead to errors.
Changes in one component will lead to changes in one centralized file, again may lead to issues.
It gives every component developer "Separation of Concern", they don't have to see, know others work while carrying out there task.

I stumbled on this thread which seeking a solution for multi-tenant application. Most articles are just about datasource (Spring HotSwapable datasource targets) etc but what you have is a separate context at the war level.
This gives me another idea of bundling my application in a way that makes it multi-tenant.
If the wars are skinny just to inject special runtimes and provide additional context path qualifies this may work for a large multi-tenant application. Common classes will be loaded at the EAR level and application contexts per war. I guess this should be ok for small number of tenants.

Related

Can multiple portlets share a singleton? [duplicate]

I have a couple of Singleton classes in a Liferay application that hold several configuration parameters and a ServiceLocator with instances to WebServices I need to consume.
I have put these classes in a jar that is declared as a dependency on all my portlets.
The thing is, I have put some logging lines for initialization in theses singleton classes, and when I deploy my portlets I can see these lines multiple times, once for every portlet, since each portlet has its own class context.
For the AppConfig class it might not be such a big deal but my ServiceLocator does actually hold a bunch of references that take a good bit of memory.
Is there any way that I can put these Singleton references in some kind of Shared context in my Liferay Portal?
The problem is that every Portlet runs in its own WAR file and aech war file has its own classloader.
Usually when I had to achieve a requirement like this, I had to put the Singleton classen in a JAR file and this JAR file in the common class loader library instead of packing it into each WAR. (In Tomcat: <tomcatHome>/common/lib or something like that)
Then you'll also have to put all dependent libraries into that common lib dir, too. Don't know how to do that in Liferay, though. For tomcat see this thread: stackoverflow.com/questions/267953/ and this documentation: http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html. Depends on the Servlet container.
Alexander's answer gives the general answer that's true with or without Liferay in mind.
Liferay (as you mention it) adds another option to this: ServiceBuilder. You'll end up with the actual instances contained in exactly one web application, and you'll have an interfacing jar that you can distribute with every dependent application. This way you can more easily update your implementation: It's easy to hot-deploy new and updated web applications to your application server - it's harder to update code that's living on the global classpath.
The global classpath (Alexander's answer) however brings you immediate success while ServiceBuilder comes with its own learning curve and introduces some more dependencies. I don't mind those dependencies, but your mileage might vary. Decide for yourself
With maven portlet you can make a common Spring component and import in the pom of each portlet.
Another solution is to use service builder.
Spring MVC portlet would be the most recommended for this.

Is there any native mechanism whereby we can override classes in an existing deployed Struts2 app?

Specifically, if we have an original .war file deployed in a application server, can one deploy a .war which provides different implementations of classes in the original file without having to modify the base code to support this?
Edit. I've formulated the problem wrongly, it's actually simpler I think. We want to expose actions from two distinct WARs in the same base path, rather than a different path for each WAR. Can it be done at the container configuration level?, or do you recommend employing something like URL rewriting?
Not easily. Generally, a deployed WAR becomes a discrete webapp within a Java EE server, and it gets its own classloader. Your second deployment will get another classloader, and although they will definitely share some ancestry, it won't be possible to reimplement things from the other WAR - your second deployment won't be able to 'see' it, because of the way the classloaders are chained together.
It is possible to rewrite running classes using a Java agent, although this is nontrivial. You can transform (rewrite incoming) classes and you should be able to rewrite live (instantiated) classes, although the problem there is that there may be objects on the heap using the old and new code.
Class rewriting is how Eclipse's Hot Code Replace works, and also how JRebel's fast redployment solution functions.
You might be able to use an AOP system like AspectJ if you really want to pursue this - but it sounds like you're trying to solve a build or deploy problem, rather than a problem where AOP would be a more fitting solution.

Do servlet containers prevent web applications from causing each other interference and how do they do it?

I know that a servlet container, such as Apache Tomcat, runs in a single instance of the JVM, which means all of its servlets will run in the same process.
I also know that the architecture of the servlet container means each web application exists in its own context, which suggests it is isolated from other web applications.
As depicted here:
Accepting that each web application is isolated, I would expect that you could create 2 copies of an identical web application, change the names and context paths of each (as well as any other relevant configuration), and run them in parallel without one affecting the other. The answers to this question appear to support this view.
However, a colleague disagrees based on their experience of attempting just that.
They took a web application and tried to run 2 separate instances (with different names etc) in the same servlet container and experienced issues with the 2 instances conflicting (I'm unable to elaborate more as I wasn't involved in that work).
Based on this, they argue that since the web applications run in the same process space, they can't be isolated and things such as class attributes would end up being inadvertently shared. This answer appears to suggest the same thing
The two views don't seem to be compatible, so I ask you:
Do servlet containers prevent web applications deployed to the same container from conflicting with each other?
If yes, How do they do this?
If no, Why does interference occur?
and finally, Under what circumstances could separate web applications conflict and cause each other interference?, perhaps scenarios involving resources on the file system, native code, or database connections?
The short answer is that the servlet container isolates the applications by using a separate classloader for each application - classes loaded by separate classloaders (even when from the same physical class files) are distinct from each other. However, classloaders share a common parent classloader and the container may provide a number of other container-wide resources, so the applications are not completely isolated from each other.
For example, if two applications share some common code by each including the same jar in their war, then each application will load their own instance of the classes from the jar and a static variable (e.g. a singleton) of a class in one application will be distinct from the static variable of the same class in the other application.
Now, take for example, that the applications try to use java.util.Logger (and presumably don't include their own instance of the Logger classes in their war files). Each application's own classloader will not find the class in the war file, so they will defer to their parent classloader, which is probably the shared, container-wide classloader. The parent classloader will load the Logger class and both applications will then be sharing the same Logger class.
Servlets in the same container will share some resources. I think it should be possible to deploy the same web application twice in the same container provided that you give each a different name and they don't collide on a particular resource. This would theoretically be the same as deploying two different servlets which just happen to have the same implementation, which we do all the time.
Some shared resources, off the top of my head (and I'm not an expert so don't quote any of this!):
Libraries (jars) in tomcat/common/lib (Tomcat 5) or tomcat/lib (Tomcat 6).
Settings in the global server.xml, web.xml, tomcat-users.xml
OS provided things, such as stdin/stdout/stderr, network sockets, devices, files, etc.
The logging system.
Java system properties (System.getProperty(), System.setProperty())
I suspect... static variables? I'm not sure if the ClassLoader design would prevent this or not.
Memory. This is the most common problem: one servlet can deny others availability by consuming all memory.
CPU - especially with multi-threaded apps. On the HotSpot JVM, each Java thread is actually an OS-level thread, which are expensive and you don't want more than a few thousand of them.
Doubtless there are more.
Many of these things are protected by a security manager, if you're using one.
I believe the isolation is in the class loader. Even if two applications use the same class name and package, their class loader will load the one deployed with the application.

Tomcat parent webapp shared by configurable children webapps

Currently, we support many clients using the same web app, but each client has a different configuration for accessing their database, setting files etc. As the client list grows, updating the web apps is becoming increasingly arduous, and the duplication of resources is a waste of memory, file space, etc..
What we'd like to do is have a parent web app which is shared by all children web apps. Then have each child web app carry only files specific to them. When the child web app starts up, Tomcat loads the web app from the parent web app and then overrides any files defined in the child web app following an identical package structure.
We've been googling around and haven't found a ready or complete solution. Solutions we've looked at:
Tomcat common/share - could handle class and JAR files, but we don't see a way to handle static and JSP resources residing above the WEB-INF dir.
CATALINA_BASE appears to be more suited for running multiple instances of Tomcat which we'd rather avoid
A Maven possible solution, but we are not big fans of Maven, so would rather avoid it also.
Anybody have suggestions or ideas on how to solve this? If Tomcat configuration is not possible, what about a different application server (such as Glassfish) or a tool for doing dynamic file updated (such as OSGi, rsync). Would like to remove the resource duplication if possible.
Thank you.
There is no such thing as "parent" or "child" webapps. It's not part of J2EE spec and AFAIK it's not supported by any application server.
That said, your problem is twofold:
1) Having shared resources. This part is pretty easy assuming "resources" means static resources (images / CSS / javascript / etc...).
If they are truly shared (e.g. you don't need to have a separate version in some of your webapps), host them elsewhere (separate "common" webapp or put Apache in front of your Tomcat and host them there.
If you do need to have "local" versions of some of those resources you may be able to do some clever conditional URL rewriting or simply write a servlet that would check whether particular resource exists locally and, if not, take it from "common" location.
Precompile your JSPs so you only have to deal with JARs.
If your Tomcat instance only hosts your apps, you can indeed put your JARs in shared (or lib in the latest version); otherwise you can deploy them with each application .
2) Simplifying deployment. I'm not really sure what the big problem is here... It's rather trivial to write an Ant (batch, shell, what have you) script that would assemble and deploy WARs based on "common" and "per-app" directory structures.
Alternatively, you may want to take a look at using JNDI to severely reduce the number of files that have to be deployed (in theory, to a single context.xml for each application).
You can build parent-child hierarchy if you use Spring at your web-apps - Using a shared parent application context in a multi-war Spring application.
I.e. you can define all shared stuff at the 'parent' context and have 'child' contexts just to use it.
If all you had was setting file and configuration changes you could manage these through the context.xml and then you can point the docBase of each application context at a common directory for all the applications to share the same source.
the drawback to this is changes to the application will require a tomcat restart.
This does not however solve your problem if you want to override logic.
A option that I am exploring for a similar scenario is to move the client custom portion into ajax widgets / gadgets. Then have it be part of the configuration files to tell the application which version of the gadget to pull for which client.
you can review documentation for having applications share a docbase here http://tomcat.apache.org/tomcat-5.5-doc/config/context.html

Running multiple versions of a servlet web application parallel

I want to run multiple versions (like myapp2.1, myapp2.2 ...) of several Java Servlet based web applications parallel.
One possibility could be to deploy each version to a separate servlet context (which should have its own class loader?!). But I think it will be hard to manage and won't be flexible, since an application is a quite large block. What if an application should contain a service in two different versions? Maybe that is not a good idea ...
The environment will be GlassFish >= 3.0.
What is a better way to run multiple versions of a servlet application parallel? Could OSGI help?
Each web application will be loaded using its own ClassLoader (at least any container I know of; I can't imagine why a container would not do this). So, it should just work. Different versions of your classes will not interfere with one another.
Make sure you do not include any of your classes in the container's own ClassLoader -- for example by putting a .jar in lib/ in Tomcat's directory (not sure of the equivalent for Glassfish). That would be shared by all web applications, and would override whatever is in the web app.
One possibility could be to deploy each version to a separate servlet context (which should have its own class loader?!).
J2EE applications use separate hierarchy of ClassLoaders and are isolated from each others. Quoting Classloaders and J2EE:
J2EE classloader hierarchy
J2EE specifies that a hierarchy of
classloaders is needed to achieve the
isolation between applications, but
leaves it to the vendors to define the
exact structure. However to comply
with the J2EE specification, most
vendors have classloaders for each of
the J2EE application components
depending on its location. Further,
these classloaders have a hierarchy
among themselves, i.e. they have a
parent-child relationship. Figure 21.5
shows a sample hierarchy of
classloaders. Note that each
application server’s classloader
hierarchy might slightly differ.
Application server vendors sometimes
tend to treat two or more of these
classloaders as one. For instance, a
certain application server might treat
Application classloader and EJB
classloader to be the same. But the
general concepts behind the hierarchy
remain the same.
Sample Classloader Hierarchy in J2EE Application Servers http://www.objectsource.com/j2eechapters/Ch21-ClassLoaders_and_J2EE_files/image016.jpg
Figure 21.5 Sample Classloader Hierarchy in J2EE Application Servers.
So, yes, each webapp would have its own ClassLoader (thanks god).
But I think it will be hard to manage and won't be flexible.
Why hard to manage? Why not flexible? How many instances are you going to run in parallel? Actually, what problem are you trying to solve? You may get better answer if you describe the real problem. So, can you elaborate a bit?
Unless you explicitly configure it to be so, all servlets are multi-threaded and can be invoked several times at once.
So, do you want several web applications with the same code but different names or several servlets inside the same web applciation with different configurations? Please edit your question with a scenario.
EDIT: You have now edited the question.
You can simply just name the war file you deploy like application20091230, application20091231, application20100101 and let Glassfish assign it to the corresponding URL. If date is not granular enough, then either a datetime or a buildnumber.
That's what we do for having several versions in a single internal test server.

Categories

Resources