I want to shared common application context in a multi-war Spring application, so i don't need to defined beans again and again. But i don't want to instantiate those beans defined in this common application context in each webapp. I only want to instantiate those beans once and share by all the webapps. Is it possible? Bare me if i'm wrong.
PS: this common application context exists in jar, which i'll import to every webapps.
1, Below article tell us how to share the common application context, but need to instantiate those beans in each webapp.
How to import spring-config.xml of one project into spring-config.xml of another project?
2, Below is another article i just read, i demo it, but still don't get what i want, beans got instantiated twice. Can someone check this section "Why would you want to use this?" in the article, i don't get it, do they have a solution there, can someone help me here, thanks a lot for your time.
http://spring.io/blog/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/
here is the demo source code in second article: https://github.com/jasonluo/ceciic/tree/master/Research/multiple-contexts-sample
Updates
The problem of case2 is because i didn't deploy as a ear file, thanks Deinum for pointing this out, i'm using tomcat, so there is no way to achieve that.
Our solution now is using REST to access the service webapp which running in a separate server.
Don't, there is usually classloader isolation going on to prevent this. Doing this right usually requires a thorough understanding of classloading, Java EE, packaging and your server.
Having that said there is way to do this as outlined in the blog you posted. You have to:
package both WARs into an EAR (this means you have to use and appserver like WildFly AS and can't just use a servlet engine like Tomcat or Jetty)
package both WARs as "skinny" WARs with at least Spring (and all its dependencies) and the shared beans (and all their dependencies) in the lib/ folder of the EAR instead of the WEB-INF/lib folder of the WARs.
Even then it depends on implementation details of the server. AFAIK it is not guaranteed to work under the Java EE specification. For example it likely won't work in GlassFish.
Update
I can't tell if the output of your demo is correct because I couldn't find a build file.
Yes, Tomcat does not support EARs, you could use Apache TomEE which is very similar and supports EARs (I don't know if TomEE does classloading in a way that makes this work). In theory you could also make use of the common classloader in Tomcat but that would be quite a hack.
There is a way to do it, using Spring Dynamic Modules, but it requires OSGi environment, which is quite different from simple Tomcat. Few articles worth reading:
Deploying Spring MVC applications to OSGi
Hello world style example
Blueprint - a further development on DM
Another blueprint documentation reference to Spring
That being said there is not a lot of up to date information about Spring with OSGi, but it's worth a try to achieve just what you said (but of course, with additional performance cost)
Related
Hello stackoverflow Users,
I have found myself working on a Java EE Web Application and I know for a fact that my application is going to be deployed into multiple environments. Each environment may have slightly different configuration of some features, e.g. remote web-service URLs. Additionaly, I would like - if possible - to have the following 2 properties met:
Per environment config should not in web-application repository
This is because I feel it does not belong there. I would not want to manage n-configurations next to my source code. Moreover, if there are secrets there, I would not want every developer to see them...
Enforce completeness of configuration
If I say that I need a certain configuration parameter/resource then it would be meaningless if it was not provided. I would not want my application to start in such case.
Please, can somebody more knowledgable and experienced help me and nudge me into the right direction?
My findings so far
Naturally, I have spent some time searching the answer already ...
Spring framework
I know that spring provides an Environment class as an abstraction of environment-specific configuration. However, I am not using Spring framework, nor does it describe how to put this configuration outside of the web applicatoin.
Java EE JNDI Service
According to the Java EE platform specification, the right way to do it would be to use env-entry, resource-ref and resource-env-ref elements in my WEB-INF/web.xml and have them bound/set to values in the web app container configuration.
This actually sounds very good, except that I don't know how to enforce the completeness of this configuration. I mean, I declare the above mentioned elements, to tell the deployer that I need them, yet I see (tested on tomcat) that application still deploys (and works incorrectly) when some, say resource-env-ref, is not bound.
I don't know how to achieve it tbh, however, if there is nothing better, it still feels like the best thing I could find. :-|
I have taken the JDNI approach.
I have added validation of configuration by introducing a custom ServletContextListener implementation.
For an ongoing project, we are looking for a possibility to dynamically download and load jar files into a running application. Apart from downloading the files (which is probably fairly straightforward), I am unaware of any solution that would automatically add the jar's to the classpath, and do discovery of the annotations (like CDI beans).
Given such a system, it would be rather handy if the #Inject annotation would not throw a runtime failure of an implementation of a class is not present (because that module-jar was not loaded).
Is there currently any such system? Does spring or OSGi fit this need?
Any ideas how close project Jigsaw would come in trying to fulfill this on application level?
I think you need OSGI, using an OSGI container like Karaf : https://karaf.apache.org
In standard java provide ServiceLoader https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
I advice you to not follow that path
It should be possible to dynamically load jar files without the usage of OGSI. The keyword are Classloaders especially when used with a proper hierarchy. The following answer should give you an idea: How should I load Jars dynamically at runtime? but keep in mind that this might cause serious security issues
You followed the path at 2. even I advice you not to do it. But now you end up in the scenario that the context of your used framework does not know this classes. You would have this problem with most IOC frameworks. Since they build up the context on startup. There are libraries for this created for development purpose (spring-loaded, spring dev tools, JRebel). If your IOC framework supports it go with it.
Regarding handling not available jars. The best point to do research on this is Spring Boot and its auto configuration mechanism. It checks if certain classes/jars (not sure to be honest) are available and add additional behavior for this cases. But still this is application startup solution and not a runtime IOC solution.
I'm creating a Java web application, making use of CDI. My War includes various Jar files that are bean sources (including the META-INF/beans.xml file). My beans are automatically discovered when running inside a Java EE container like JBoss (I'm currently using JBoss AS 7.1.1). This much is working well.
I want to be able to extend the web application, ideally by allowing it to load classes from Jar files stored in a configurable location (so at a location specified by a system property). This too is fine, since I can use a ClassLoader to resolve classes and resources. What I'm missing is the ability to have CDI scan these external Jar files and include their beans.
This would allow my application to host plug-in functionality including new REST resources. I don't mind if I had to restart the application for it to pick up classes and resources contained within these external Jar files.
I can see no way of achieving this. Is this even something that should be attempted in this kind of environment?
I can see no way of achieving this.
You actually have two options:
Use the CDI extension mechanism to work with beans / bean-archives
at startup time and to modify them in the way you want. Have a look at the examples provided in the documentation, this should give you a start.
Work with the BeanManager at execution time. Have a look at this similar question.
A day ago my application was one EAR, containing one WAR, one EJB JAR, and a couple of utility JAR files. I had a POJO singleton class in one of those utility files, it worked, and all was well with the world:
EAR
|--- WAR
|--- EJB JAR
|--- Util 1 JAR
|--- Util 2 JAR
|--- etc.
Then I created a second WAR and found out (the hard way) that each WAR has its own ClassLoader, so each WAR sees a different singleton, and things break down from there. This is not so good.
EAR
|--- WAR 1
|--- WAR 2
|--- EJB JAR
|--- Util 1 JAR
|--- Util 2 JAR
|--- etc.
So, I'm looking for a way to create a Java singleton object that will work across WARs (across ClassLoaders?). The #Singleton EJB annotation seemed pretty promising until I found that JBoss 5.1 doesn't seem to support that annotation (which was added as part of EJB 3.1). Did I miss something - can I use #Singleton with JBoss 5.1? Upgrading to JBoss AS 6 is not an option right now.
Alternately, I'd be just as happy to not have to use EJB to implement my singleton. What else can I do to solve this problem? Basically, I need a semi-application-wide* hook into a whole bunch of other objects, like various cached data, and app config info. As a last resort, I've already considered merging my two WARs into one, but that would be pretty hellish.
*Meaning: available basically anywhere above a certain layer; for now, mostly in my WARs - the View and Controller (in a loose sense).
Edit: I should really be calling it Java EE rather than J2EE, shouldn't I?
Edit 2: Many thanks again to #Yishai for all the help. After some trial-and-error it looks like I've figured out how to use a single ClassLoader across WARs under JBoss 5. I'm detailing this below for my own sake, and hopefully others will find this useful as well.
N.B. this is rather different from doing this under JBoss 4 (see Yishai's answer or my links below).
Instead of writing a jboss-web.xml for each WAR, and a jboss.xml for ear EJB-JAR, put a jboss-classloading.xml file in each WAR, in the same location as the DD (web.xml). The contents of jboss-classloading.xml should be:
<?xml version="1.0" encoding="UTF-8"?>
<classloading
xmlns="urn:jboss:classloading:1.0"
name="mywar.war"
domain="DefaultDomain"
parent-domain="Ignored"
export-all="NON_EMPTY"
import-all="true">
</classloading>
This follows from the JBoss CW here, whereas what (I think) works for JBoss 4.x is described here. More general info on JBoss classload(ing/ers):
Overview
History
Use cases
As best I can tell, the JBoss community wiki docs are pretty lacking for JBoss 5 in comparison to JBoss 4.
Although the EJB3.1 spec introduces singleton and your version of JBoss doesn't support it, you can use the JBoss #Service annotation to create a singleton. Instructions here. Also, it seems that you have JBoss configured to isolate your ejb jars and wars from each other. You don't have to do that. You can look at the loader-repository tag in the jboss specific xml files so that your whole ear shares one classloader (or perhaps that at least the two wars share one classloader).
All that being said, I agree with #duffymo, that a singleton which shares state between the two wars is an idea that you should be walking, if not running away from.
Edit: Regarding singletons, I suggest you look at questions like this one (which also has some nice balance in the comments).
The idea of having an object hold cached state in and of itself is ok, especially with EJB3 where you can inject your state instead of statically referencing it (if you use the #Service annotation, then you want the #Depends JBoss specific annotation). That being said, if you were using a "proper" singleton here, then I would expect that your only problem with the fact that your WARs have two separate classloaders is the extra memory footprint. Otherwise you are into the problematic area of singletons (where they have to be initialized to be used, everything that uses them has to ensure they are initialized first, and of course all code gets highly coupled with their being initialized).
Where Singletons are really really bad is where they store state so that one class can change state and another class picks it up. It is basically a no-no in EJBs until 3.1, and even then it makes a lot of concurrency issues.
Edit (further): So you want to go with the classloader repository. I use JBoss 4.2.3, so I don't necessarily know all of the ins and outs of JBoss5 (which did rewrite its classloader although they say it is almost fully backwards compatable), however in 4.2.x by default your configuration causes no problems because all the ears deployed on the server share the same classloader (the "unified classloader"). What I suspect is that the server you are deploying to has the configuration differently, so I'm not quote sure how to interact with it, but what you have to do is add a file called jboss-app.xml in your ear (in the same location as the application.xml) that looks something like this:
<?xml version="1.0"?>
<!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN"
"http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
<jboss-app>
<loader-repository>
com.yourcomany:archive=yourear
</loader-repository>
</jboss-app>
That is for JBoss 4.2. 5.1 has the same type of tag, here is the xsd. It has the same loader-repository concept.
That should be it. That is, as long as your ejb-jar, war, etc. don't have it, then they don't need it. However, your wars (in jboss-web.xml - same location as the web.xml) may need the same thing. In this case as long as you name the repository exactly the same way (if I understand correctly - never tried it myself) they will share the same classloader. The same goes for the EJB as configured in the jboss.xml that goes in the same location as the ejb.xml.
This might make it a bit clearer.
I'd configure a separate object pool on your app server so it only contained the single instance.
Why you would want to do this is the real question. Sounds like all your apps will be coupled this way. And Google is eradicating singleton from its apps. Why are you seeing fit to bring it back?
You can use a MBean and bind it to JNDI, then retrieve it wherever you want to use it.
The MBean might be deployed in a .sar file
If you are using Java EE 6, then it supports singleton EJBs.
If practical, simply take the class that has the singleton, put it in a JAR, take the JAR OUT of the the EAR, and add the JAR to the JBoss classloader (via the system classpath, or a some lib directory). This puts the class in a single classloader shared by both WARs.
The singleton will not be able to "see" anything in your applications WARs etc, as they're in a lower classloader.
However, there's nothing stopping you from injecting into the singleton (at server startup) a factory class, that originates from the WARs et al, and THAT class has access to all of the apps classes. That makes the singleton more of a simple container.
But this is straightforward to do.
Also, if you do this, make sure when you shut down you application, that any instances held by this singleton are freed. Any class reference by the singleton will not be GC'd when you undeploy the application. So, if you have a reference to your app stored in the singleton, then the server holds a reference to the singletons classloader, that classloader holds a reference to your singleton class, which holds reference to you apps class, which holds a reference to the apps CLASSLOADER, and THAT holds a reference to all of the classes in your app. Not a nice mess to leave behind.
To summarize the issue I'm encountering, I have an EJB which uses version A of a library (let's call it dep-vA.jar). dep-vA.jar is packaged in the root of the EJB's jar file. The domain lib folder in the application server contains version B of the same library (let's call it dep-vB.jar). When calling the EJB, I get an error due to dep-vB.jar file being loaded rather than dep-vA.jar.
I guess the first part of this question is, does Sun One Application Server v9.1 isolate EJBs from each other? I was under the impression that it does. But it seems like another application loaded dep-vB.jar and this EJB is directly using it without loading its own.
The second question is, if the app server does isolate EJBs, does it load dependencies from the EJB's jar file before looking in the application server's lib folders? I was under the impression that this is also true, but maybe not...
Is anyone familiar enough with Sun application servers to explain why dep-vB.jar is being loaded rather than dep-vA.jar? Is there any way to get it to load dep-vA.jar without changing what's in the application server's lib folders? (I would hesitate to do anything that might affect other applications on the server)
Thanks.
I guess the first part of this question is, does Sun One Application Server v9.1 isolate EJBs from each other? I was under the impression that it does. But it seems like another application loaded dep-vB.jar and this EJB is directly using it without loading its own.
According to Sahoo (which is a GlassFish developer), the Java EE spec does not mandate class loading isolation among modules of a single ear so the behavior can be different from one app server to another. With Sun ONE, my understanding of the documentation is that EJB-JARs are isolated.
The second question is, if the app server does isolate EJBs, does it load dependencies from the EJB's jar file before looking in the application server's lib folders? I was under the impression that this is also true, but maybe not...
It's a parent-first strategy (and to my knowledge, Sun ONE allows to change the delegating mode for webapps only).
That being said, what happens if you list dep-vA.jar in the Class-Path entry of the MANIFEST.MF of the EJB-JAR?
See also
Chapter 2 Class Loaders of the Sun Java System Application Server Platform Edition 9 Developer's Guide
Packaging EJB 3 Applications
I haven't used that particular server, but I do know that in WebSphere, there is an option to use PARENT_FIRST or PARENT_LAST classloading. You would be looking for an equivalent of PARENT_LAST where the classes are loaded from the EAR first before going up to the server.
I would assume that such a configuration is possible in any app server, as you should always be able to enforce your application specific jars to be loaded over any others.