I'm working on a project that have several webapps (WARs) built with Maven and deployed in a Java EE.
These WARs share several common business JARS (like one containing domain objects which are loaded from hibernate) and other framework JARs like Spring and Hibernate.
They use Spring MVC, and the Application Context loads Hibernate. As each WAR has its own Classpath in the servlet container, the Hibernate cache (EHcache) is not shared.
What I'd like is to share the cache and also the hibernate session factory bean (as well as other common beans) betweeen the different WARs. I think this is possible by repackaging those WARs inside an EAR and then I'd have to make a spring configuration XML using those commons beans and in the WAR's Spring XML use something like SingletonBeanFactoryLocator from what I've read.
What I'm asking here is if there is a simple way to do this, minimizing changes to the WARs' POMs
Note: I'm familiar with WARs, tomcat and servlets, but not so much with EARs.
Thanks in advance.
Hmmm... Most Java EE containers use isolated classloaders for WARs, even in an EAR (even if the Java EE spec does not mandate class loading isolation among modules of a single EAR) so I wouldn't expect to much from an EAR packaging, especially if you want your application to remain portable (i.e. if you don't want to rely on any app server specific behavior).
Now, if really it makes sense to share your session factory and your 2nd level cache between several applications, maybe consider merging them in a single WAR. That would be the easiest way IMO. But I'd be tempted to ask why are they separate then? When applications are separate, they have most of time separate governance and I don't know if deploying them together would be a good idea in such case.
And if merging the WARs is not an option, please tell us which container you are using.
Have you considered making use of a coherent clustered L2 cache? If you're using multiple app servers you might see more benefit then as they would all be sharing the same coherent cache
Using a shared parent application context in a multi-war spring application
http://blog.springsource.org/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/
Related
I made an 'Enterprise application' in NetBeans and I added hibernate as well as some hibernate mapping files to the web application project. Additionally, I need to add a 'HibernateUtil.java', 'hibernate.cfg.xml' and 'hibernate.reveng.xml' in the web application.
However I wanted to manage these entity/mapping classes in my EJB project as they seem to behave like enterprise beans and I wanted to separate them from my web application. I was wondering how this can be done and how I could access the entities ejb's in my web application project through dependency injection? There was also an option in the 'New' menu: 'Create session bean for Entity classes' and wondered if it has any use in relation to the question?
EDIT: Using EJB3
You shouldn't have put your JPA-related files to a WAR at the first place. Keep them in EJB JAR and reference your JAR from WAR as a provided runtime dependency in Maven (or use provided scope's analogue for whichever build tool you prefer). Keeping your business logic in EJB JAR will pay off when you'll need more than one WAR in your EAR (different security realms, etc.)
In general, this is as simple as putting all your JPA-related stuff in EJB JAR, they will then be available for dependency injection from WAR-provided managed beans as well.
Also, consider replacing your Hibernate-specific configurations with JPA and let application server to resolve all the stuff for you.
Currently I have a Spring project that uses Spring JPA to work with data objects and my database. All of it's functionality can be accessed by calling a single facade bean. I want to make a web application based on this data model, but I don't want to extend this project any further. Instead I would like to separate my persistence and service layers from an actual web application layer. That said, I want to package this project into a ".war" file and deploy it on my Tomcat instance. Upon demand from any other application working on Tomcat I would like to have this other application to be injected with the facade bean from my ".war".
I'm sort of new to Tomcat, and googling doesn't really help me much. So here are problems and questions that I have with this concept:
Is this the right way to do what I want? What I mean is I want behavior provided by my current Spring application to be accessible and reusable by different web applications working on one server. This might be a common case and I would like to know if this is ok as a solution.
If I have this facade bean in XML context or in annotation context of my project, how can I make this bean visible to any other application working on the same Tomcat instance upon being deployed? What should I write in my web applications to have them wired with this bean? If I want this bean to be a singleton and have all calls to it's functionality synchronized, should I do this through my code/context, or can I have Tomcat somehow take care of this for me?
Thanks in advance.
You might want to consider a REST API approach. You can't do "cross application injection" with Spring and JNDI can be cumbersome to use.
Webapps (the things that run in a servlet container like tomcat) are isolated from each other, by design. Sharing may well be a bad idea. However, to share, you can use JNDI. Setting up JNDI in tomcat 7 is described here. You will need a custom resource factory.
I have one WAR ( app.war ) and one container ( Tomcat, Jetty, Glassfish, whatever ).
My goal is to deploy, on demand, hundreds of instances of this same web application on the container.
http://foo/app1 --> app.war
http://foo/app2 --> app.war
http://foo/app3 --> app.war
...
http://foo/appN --> app.war
Some obvious ways of achieving this:
In Tomcat, create one context.xml file for each app ( named appN.xml ), all pointing to the same WAR. Other containers have similar methods
Problem with this approach: It will explode the WAR N times, taking up a lot of disk space
Use symbolic links to create webapp/{app1,app2,appN} folders pointing to an exploded version of app.war. This prevents the disk space explosion, but the JVM is still loading many duplicate JARs to memory
Use some shared lib folder to contain most jars ( and a combination of the previous two options ).
I wonder if there is a better method to do this. Ideally, creating a new instance should not take up ANY more disk space ( other than marginal configuration files ) and only take up memory related to thread execution stacks and other runtime allocations.
Any ideas?
Jetty added support for what you looking for a while back with what are called overlays.
http://wiki.eclipse.org/Jetty/Tutorial/Configuring_the_Jetty_Overlay_Deployer
Copying a bit from the wiki page:
You can keep the WAR file immutable, even signed, so that it is clear which version you have deployed.
All modifications you make to customise/configure the web application are separate WARs, and thus are easily identifiable for review and migration to new versions.
You can create a parameterised template overlay that contains common customisations and configuration that apply to many instances of the web application (for example, for multi-tenant deployment).
Because the layered deployment clearly identifies the common and instance specific components, Jetty is able to share classloaders and static resource caches for the template, greatly reducing the memory footprint of multiple instances.
Apologies for being a little bit off-topic, but in my view, your scenario shouts "multi-tenancy" application, so that you've got a single application which will service multiple "tenants" (customers).
With regard to multi-tenancy setups, the following considerations would have to be considered:
Customers cannot access each other's data (if they the data is stored in the same database, same schema and using "discriminator" fields to separate the data). This could be achieved by using Spring Security with Access Control Lists
Hibernate has built-in support for multitenancy apps from version 4.0.
These two SO questions may be useful as well
Multiple Entity Manager issue in Spring when using more than one datasource (for using different data sources (different databases or just different schemas on the same database per customer).
Multi tenancy support in Java EE 6
Benefits of multitenancy:
Shared code means that a bug fixed for one customer is fixed for all (this can be a disadvantage as well if different customers have different views on what constitutes a bug and what constitutes a feature).
Clustered deployment can share the load between customers (however, need to ensure that peak capacity is available for all customerS).
Downsides:
Code is going to be a bit more complex as queries need to ensure that the "discrimination" between customers works without accidentially exposing customers to each others data.
You could configure Apache on the front end (mod_proxy/mod_proxy_ajp) to point named virtual hosts to a single WAR deployed on Tomcat. Your application should be designed/written in a way to service all request -- per website name specific configuration could be stored in a database or as a configuration file within your application -- your app would just need to probe the user's requesting domain name to ensure the correct settings are applied (once per session). Generally speaking, you should be able to solve this with one application. Great developers are LAZY.
If you're using Jetty, you can add contexts programmatically.
WebAppContext webapp = new WebAppContext();
webapp.setBaseResource(myBaseDirectory);
webapp.setContextPath(myContextPath);
Just do this in a loop for all your contexts. It should have close to zero diskspace overhead.
There's probably a similar way to do it in Tomcat.
Well if this is for an experiment then any of the methods you listed can work.
If this is for production then I would recommend against this. While I have not tested ALL containers, the containers i have used lead me to be believe it is much more resilient to simply provision headless VMs with containers. Linux VMs can be very small and with VM technology you can add or subtract as many instances as needed.
If you truly want to have a dynamically growing solution then you should look to eliminate single points of failure rather then try to lump your entire world into one.
If you truly need "up to the second" load expansion/contraction then you should look at AWS or CloundFoundry.
I'm working on a layered business application written in Java that should be packaged as an EAR file and deployed to a JBoss application server. There's a web-application layer, a service layer, a domain layer but no persistence layer. At least on paper.
What is the best practice for deploying the different layers? In our team we have a little religious war going on between:
Packaging each layer in its own JAR file (e.g. in its own Maven module), and adding each module to the EAR file, OR
Bundling everything together in a single JAR file, with each layer mapped to a package naming convention.
Are there other possibilities I'm missing? What are the best practices in this area? Are there any online or offline resources I could consult about this?
In my company, we bundle each layer into its own JAR. Then we include it in a WAR.
If you don't have any EJBs that need managed, there's no real advantage to using an EAR over a WAR for deployment.
Whichever approach you choose, make sure you actually gain value out of it. In other words, don't serve the architectural principle (package/jar) let the architecture principle serve you.
You need to balance separation of concerns with efficiency. The more projects you have the more cumbersome things become, but if you have one project, that can also be cumbersome.
Look at your requirements, context and size of your application and decide which approach is going to serve you best.
We currently have a web application loading a Spring application context which instantiates a stack of business objects, DAO objects and Hibernate. We would like to share this stack with another web application, to avoid having multiple instances of the same objects.
We have looked into several approaches; exposing the objects using JMX or JNDI, or using EJB3.
The different approaches all have their issues, and we are looking for a lightweight method.
Any suggestions on how to solve this?
Edit: I have received comments requesting me to elaborate a bit, so here goes:
The main problem we want to solve is that we want to have only one instance of Hibernate. This is due to problems with invalidation of Hibernate's 2nd level cache when running several client applications working with the same datasource. Also, the business/DAO/Hibernate stack is growing rather large, so not duplicating it just makes more sense.
First, we tried to look at how the business layer alone could be exposed to other web apps, and Spring offers JMX wrapping at the price of a tiny amount of XML. However, we were unable to bind the JMX entities to the JNDI tree, so we couldn't lookup the objects from the web apps.
Then we tried binding the business layer directly to JNDI. Although Spring didn't offer any method for this, using JNDITemplate to bind them was also trivial. But this led to several new problems: 1) Security manager denies access to RMI classloader, so the client failed once we tried to invoke methods on the JNDI resource. 2) Once the security issues were resolved, JBoss threw IllegalArgumentException: object is not an instance of declaring class. A bit of reading reveals that we need stub implementations for the JNDI resources, but this seems like a lot of hassle (perhaps Spring can help us?)
We haven't looked too much into EJB yet, but after the first two tries I'm wondering if what we're trying to achieve is at all possible.
To sum up what we're trying to achieve: One JBoss instance, several web apps utilizing one stack of business objects on top of DAO layer and Hibernate.
Best regards,
Nils
Are the web applications deployed on the same server?
I can't speak for Spring, but it is straightforward to move your business logic in to the EJB tier using Session Beans.
The application organization is straight forward. The Logic goes in to Session Beans, and these Session Beans are bundled within a single jar as an Java EE artifact with a ejb-jar.xml file (in EJB3, this will likely be practically empty).
Then bundle you Entity classes in to a seperate jar file.
Next, you will build each web app in to their own WAR file.
Finally, all of the jars and the wars are bundled in to a Java EE EAR, with the associated application.xml file (again, this will likely be quite minimal, simply enumerating the jars in the EAR).
This EAR is deployed wholesale to the app server.
Each WAR is effectively independent -- their own sessions, there own context paths, etc. But they share the common EJB back end, so you have only a single 2nd level cache.
You also use local references and calling semantic to talk to the EJBs since they're in the same server. No need for remote calls here.
I think this solves quite well the issue you're having, and its is quite straightforward in Java EE 5 with EJB 3.
Also, you can still use Spring for much of your work, as I understand, but I'm not a Spring person so I can not speak to the details.
What about spring parentContext?
Check out this article:
http://springtips.blogspot.com/2007/06/using-shared-parent-application-context.html
Terracotta might be a good fit here (disclosure: I am a developer for Terracotta). Terracotta transparently clusters Java objects at the JVM level, and integrates with both Spring and Hibernate. It is free and open source.
As you said, the problem of more than one client web app using an L2 cache is keeping those caches in synch. With Terracotta you can cluster a single Hibernate L2 cache. Each client node works with it's copy of that clustered cache, and Terracotta keeps it in synch. This link explains more.
As for your business objects, you can use Terracotta's Spring integration to cluster your beans - each web app can share clustered bean instances, and Terracotta keeps the clustered state in synch transparently.
Actually, if you want a lightweight solution and don't need transactions or clustering just use Spring support for RMI. It allows to expose Spring beans remotely using simple annotations in the latest versions. See http://static.springframework.org/spring/docs/2.0.x/reference/remoting.html.
You should take a look at the Terracotta Reference Web Application - Examinator. It has most of the components you are looking for - it's got Hibernate, JPA, and Spring with a MySQL backend.
It's been pre-tuned to scale up to 16 nodes, 20k concurrent users.
Check it out here: http://reference.terracotta.org/examinator
Thank you for your answers so far. We're still not quite there, but we have tried a few things now and see things more clearly. Here's a short update:
The solution which appears to be the most viable is EJB. However, this will require some amount of changes in our code, so we're not going to fully implement that solution right now. I'm almost surprised that we haven't been able to find some Spring feature to help us out here.
We have also tried the JNDI route, which ends with the need for stubs for all shared interfaces. This feels like a lot of hassle, considering that everything is on the same server anyway.
Yesterday, we had a small break through with JMX. Although JMX is definately not meant for this kind of use, we have proven that it can be done - with no code changes and a minimal amount of XML (a big Thank You to Spring for MBeanExporter and MBeanProxyFactoryBean). The major drawbacks to this method are performance and the fact that our domain classes must be shared through JBoss' server/lib folder. I.e., we have to remove some dependencies from our WARs and move them to server/lib, else we get ClassCastException when the business layer returns objects from our own domain model. I fully understand why this happens, but it is not ideal for what we're trying to achieve.
I thought it was time for a little update, because what appears to be the best solution will take some time to implement. I'll post our findings here once we've done that job.
Spring does have an integration point that might be of interest to you: EJB 3 injection nterceptor. This enables you to access spring beans from EJBs.
I'm not really sure what you are trying to solve; at the end of the day each jvm will either have replicated instances of the objects, or stubs representing objects existing on another (logical) server.
You could, setup a third 'business logic' server that has a remote api which your two web apps could call. The typical solution is to use EJB, but I think spring has remoting options built into its stack.
The other option is to use some form of shared cache architecture... which will synchronize object changes between the servers, but you still have two sets of instances.
Take a look at JBossCache. It allows you to easily share/replicate maps of data between mulitple JVM instances (same box or different). It is easy to use and has lots of wire level protocol options (TCP, UDP Multicast, etc.).