How to extend Spring container to be deployment specific? - java

Due to our requirements, we will have views and usecases that are deployment specific. Deployments will have generic and deployment specific parts (beans). This means that we would probaly need one context.xml file that would contain the generic beans for all deployments, and then deployment specific deploymentContext.xml for each deployment. This means that some POJOs exists in one deplyment, but not the other.
My questions:
1) is it possible to have deployment specific context files to extend the generic context file?
2) is it possible to describe a class in the deployment specific context file, that already exists in the generic context file? I.e. It would override the bean described in the generic context file, as in class inheritance.
3) is the approach described above feasible, or should the build descriptor instead dynamically generate the context.xml file? I would prefer the extension approach...
4) if I deploy all deployment specific contexts, but remove some of the POJO classes from the src directory, will the application break upon deployment or only after I try to instantiate the bean that does not exist?
Thanks a lot!

Not exactly the way you are asking, But Use of #Profile suits here
#Profile("dev")
public class SomeBean{
}
This bean will be only come to action if the profile set is dev
Document
spring-3-1-m1-introducing-profile
Also See
Is there any way to enable or disable the Spring bean definition in applicationContext.xml file?
How to set dynamically a bean reference in Spring?

Related

Excluding a CDI Bean based on a PropertyFileConfig (DeltaSpike, WebSphere 8.5.5)

I am trying to exclude a Bean implementation using the DeltaSpike 1.0 #Exclude-Annotation. The exclusion should be based on a property value like this:
#Exclude(onExpression = "providerimplementation!=mock")
I created a PropertyFileConfig returning my .properties file name to let DeltaSpike pick up the configured value and used this #Exclude in two different implementing beans, each of them being excluded like above.
The configuration is included in an EAR as a .jar file and both implementations sit in different .jar files inside the EAR.
I am trying to deploy the whole archive onto a WebSphere 8.5.5 Server and on startup I get a javax.enterprise.inject.AmbiguousResolutionException for the injection point.
It seems to me that the PropertyFileConfig is not picked up before the expression resolution, although I found references to this kind of pattern (http://deltaspike.apache.org/core.html#exclude and https://groups.google.com/forum/#!topic/java-config/xsleMKST3rU), so I wonder what's wrong with my setup.
First answer :
Unfortunately, properties defined via the PropertyFileConfig facility can't be used with #Exclude.
That's because the extension ConfigurationExtension only registers PropertyFileConfig at the end of the container initialization (which is problably mandatory as PropertyFileConfig classes are used as CDI Beans)
Instead you have to use the default ConfigSource implementations :
http://deltaspike.apache.org/documentation/configuration.html#_configsources_provided_by_default
or create your own custom ConfigSource
In particular a quick workaround here, is to defined your property in the default property file : META-INF/apache-deltaspike.properties
instead of a custom property file
Edit :
In fact my previous answer is incomplete (at least with the last version of DeltaSpike (1.3.0 today)) :
the javadoc for PropertyFileConfig now documents this limitation AND shows another way to configure custom property files using the serviceloader facility :
http://deltaspike.apache.org/javadoc/1.3.0/org/apache/deltaspike/core/api/config/PropertyFileConfig.html

Spring 3 Application Context loading

I am a bit familiar with Spring framework but am still having lots of question concerning use of spring from project architectural view point. Now I am setting up Spring 3 and a Maven web application and am willing to try out all the the fancy component-scan's and autowiring features however this is where I get confused.
I am trying to break the project into sub-modules. And at some point these sub-modules may include something-context.xml in classpath*:resource/META-INF, like for instance when I will want to define a datSource related stuff in a separate module. So that's fine spring let's you load context files from within class-paths of all of the jars.
But here is where it gets vague - say I am using component scan. I am obviously using spring DispatcherServlet and it needs a servlet context to be loaded, and then there is a global application context parameter specified in web.xml contextConfigLocation.
So now servlet context config has a component-scan feature enabled for com.mycom.project.controllers and context loaded in the global contextConfigLocation has a context loaded with component scan feature for package com.mycom.project also searches for classpath*:META-INF/spring/*-context.xml.
So my question is - does this load controller's twice given that component scan is used for a for com.mycom.project.controllers and com.mycom.project? Or is it all loaded into one huge container and the contextConfigLocation parameter for either DispatcherServlet or global declaration is sort of access issue ? As in DispatcherServlet will reach only what's defined in servlet-context.xml but won't be able to use anything else?
And if my assumption is wrong, could I have a suggestion on how to manage multi-module project issues?
Thanks.
Yes, you might run into trouble. See this link for how to solve your problem.
#Service are constructed twice
The way you proceed when creating modules seems valid to me. You have a context.xml file for each module and all will get loaded once you load the application. Your modules are self-contained and can also be used in different environments. That's pretty much the way I'd also do it.

How to load app-wide settings at startup (for Spring3 webapp)?

I am in the basic stages of writing a Spring3 MVC webapp with Hibernate. I want all of data model classes to be able to access basic configuration values for example, database table prefix name, etc. I want this option, so I (or other developers) can change things on the fly by modifying them in the .properties file.
Is my best bet to create a Config class in a util package with a static block that loads a bunch of properties from a .properties file? I suppose the class itself could be static with a variety of getters to access the values within.
If I choose the method above, how could I insure the application didn't load (Failed gently) if for some reason the .properties file I have specified was not able to be loaded? With exceptions?
If my way stinks, what might be a better scenario?
Thanks!
That's a fine approach IMHO. If you would explicitly declare a bean for this class, like
<bean id="myConfig" class="com.yourcompany.yourproject.Config"/>
spring will fail at startup if it cannot instantiate the bean. So if the properties file is unreadable/not available just throw an unchecked Exception from Configs constructor.
if -for some reason- you enabled lazy loading globally you have to explicitly disable it for this bean, otherwise you won't get a failfast solution
<bean id="myConfig" class="com.yourcompany.yourproject.Config" lazy-init="false"/>
EDIT:
another nice feature of this scenario is that you can tell maven to 'filter' the resource (the .properties file), and you can get all the maven variables. This is how my prop file looks (I use this info for the About dialog. Does anybody ever opens an about-dialog btw?)
project.version=${project.version}
project.name=${project.name}
project.organization.name=${project.organization.name}
project.url=${project.url}
project.description=${project.description}

Overwrite configuration for Spring project from outside

I'm developing a Spring application which shall be used by any kind of other application, no matter if that is a Spring project, a web application or even a simple single-class console application. The application who uses my project will just have to add the JAR file with my application.
So my project has a static factory class that gets and returns a bean from its Spring context which acts as an access object to access all public available functions of my project.
That part is already working.
But I need the developer of the application that uses my JAR to be able to overwrite certain configurations in my project without editing the config files in the JAR itself. At the moment those settings should be overwritable:
- the data source and hibernate bean configuration
- the jasypt (encryption) bean configuration
- the log4j settings
How do I make those settings overwriteable with configs from outside the jar?
Greetings
touchdown
Maybe a good solution would be a configuration that the user could override, for this take a look into:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
Specially to #Configuration and #Bean
Maybe you could have a configuration class implemented and the user can override it. After extending the class and overwrite some methods that provides some beans the user shall inform it to your factory that will do nothing else than
new AnnotationConfigApplicationContext(userConfigurationClass);
If you want to replace the complete configuration, than the easyest way would be to have a parametrized factory that takes an alternative configuration file as its argument.
If you need it a bit more fine grain (lets say up to 10 parts), than you can split your application xml in several smaller once, and use again a configurable factory that allows to exchange the smaller xml files.
So I got a solution that is working for me.
I put an general import for override context-XMLs at the bottom of my main application context:
<import resource="classpath*:project/package/config/override/or-*.xml" />
So all the user has to do is to create the package "project/package/config/override" in his classpath (e.g. resource folder) and place matching XML files in it with new bean definitions.

Can I dynamically load additional Spring configuration files into an existing WebApplicationContext?

Upon starting my webapp within Tomcat 6.0.18, I bootstrap Spring with only what is necessary to initialize the system -- namely, for now, database migrations. I do not want any part of the system to load until the migrations have successfully completed. This prevents the other beans from having to wait on the migrations to complete before operating, or even instantiating.
I have a startup-appcontext.xml configured with a dbMigrationDAO, a startupManager which is a ThreadPoolExecutor, and lastly, a FullSystemLauch bean. I pass a list of configuration locations to the FullSystemLaunch bean via setter injection. The FullSystemLaunch bean implements ServletContextAware, gets a reference to the current WebApplicationContext and thus I can have a ConfigurableListableBeanFactory. Unfortunately, this bean factory isConfigurationFrozen() returns true, so by calling beanFactory.setConfigLocations(configLocations) has no effect.
Can I accomplish this or is Spring preventing me from doing so because it's a bit out of the ordinary? It seems reasonable if understood, but also a bit dangerous. And yes, I'm willing to blow away the current context b/c the currently loaded Singletons are not needed once initialization is complete.
Thank you for the help.
My opinion would be to allow Spring to initialise your beans is it sees fit - in the order of their declared dependencies.
If you need database migrations there are a couple of patterns to have them run first:
if you're using Hibernate/JPA make your sessionFactory/persistenceManager depend-on the migration beans;
if you're using plain JDBC create a wrapper DataSource and in its init-method invoke the migrations ( code sample)
The advantage is clear: simplicity.
You could use the existing context as parent context for the other contexts, although I doubt that you could replace the existing WebApplicationContext.
If you use EAR - WAR packaging, you get this out-of-the-box (sort of) by loading an application context from the EAR and then adding one in the WAR.
Not sure whether this is applicable in your situation.
Could lazy-initialization be an alternative for what you are trying to achieve?
Possible XmlBeanDefinitionReader can help you?
you can upcat the WebApplicatonContext to ConfigurableWebApplicationContext
then use the setConfigurations method.
dont forget refresh;
There was the same task and I created two contexts: startUpContext.xml and applicationContext.xml. In startUpContext.xml there is a bean, which triggers loading of appliationContext.xml. (application context location is configured in startUpContext.xml as a property of a trigger). And finally the trigger replaces locations of the current context and refreshes it:
applicationContext.setConfigLocations(locations);
applicationContext.refresh();
(startUpContext.xml is loaded with a standard spring context loader listener)

Categories