I have a multi-module (maven) spring build. All the modules publish some beans, and most also consume beans defined further down the dependency graph. Although most of it is annotation declared beans, almost every module also has one or two xml-declared beans.
Although we have a half-decent solution, but I am really wondering what is the correct/optimal way to organize the xml files in this scenario? Do you use import between the modules or is there some other way ? Do you put all the xml files in one place or spread them around according to the dependency graph? How does your solution handle partial spring contexts (typical integration tests) ?
I'd also like to have this organized in a way that lets me leverage my IDE's spring support optimally (IDEA and a few eclipse users).
We use wildcarded imports in the modules to allow other modules contribute beans to the module declaring the import:
<import resource="classpath*:com/acme/**/*-core-support.xml" />
Modularity
Modules that want to contribute to the "host" just have to place a correctly named files in src/main/resources/com/acme in this case to be picked up automagically. If you use classpath scanning (by <context:component-scan /> it will become even easier).
Another thing that helps in that regard is some small Spring extension that picks up beans of a given type and republishes them in ApplicationContext again. By doing something like this:
<plugin:list id="beanList" class="com.acme.MyCoolPluginInterface" />
<bean class="com.acme.MyPluginHost">
<property name="plugins" ref="beanList" />
</bean>
In combination with the wildcarded import this will:
Collect all beans found in the ApplicationContext that implement MyCoolPluginInterface and wrap them in a list registered as beanList in the ApplicationContext.
Allow the MyPluginHost to reference that list.
In fact, you now can simply extend your app by adding plugin modules to the classpath (aka dependency in Maven).
That tiny Spring extension is called Spring Plugin and published under Apache 2 licence. See http://github.com/SpringSource/spring-plugin for more info. There's also a more advanced sample project at Github, that shows how this works and improves modularity at GitHub. The app is sample code for my "Whoops! Where did my architecture go?" presentation which you can see the slides here or watch a recording here.
Different environments
Usually we configure our apps to run in the target environment (using JNDI lookups and stuff). Of course you would like to use the standard PropertyPlaceholderConfigurer mechanisms to externalize configuration that has to be touched by admins or will change through various environments.
For integration tests we usually have additional config files in src/main/test that get loaded additionally to the normal config files overriding the critical beans that tie the configuration to the environment. E.g. if you have a datasource in your normal config file
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource" />
you would override this in your test-context.xml by using
<bean id="dataSource" class="...DataSource" />
<!-- config -->
</bean>
and importing that after the original one in the test class
#ConfigurationContext(locations = {"app-context.xml", "test-context.xml"})
public FooBarIntegrationtest {
// ...
}
We simply create the application context from multiple XML config files based on usage.
For example, for testing without a server, the context is created by using all the config files in each service module.
When deployed, we access the services via Spring Remoting, and thus the client uses an application context that is initialized via an XML config which defines the proxy beans that enable remoting. Meanwhile the services are confgured by the same XML files as used by the test cases, but the application context is now loaded by either the DispatcherServlet or an EJB or MDB.
This setup allows us to tailor the Application Context for each scenario without having to duplicate any information in configuration files, which keeps maintenance much simpler. Also, there is no hard dependency between config files via imports, since that is handled at the layer above that actually creates the ApplicationContext.
Can't comment on the IDE support since we are not using it yet.
Related
I am going to create Java Application that can load external jar files at runtime by FileChooser. I am using Spring Framework, and I want to load jar file and its applicationContext.xml file and inject its dependencies dynamically. I tried to achieve this by OSGi, but it seems very complicated so that I am searching another appropriate variants.
I want to make something like Intellij IDEA plugin installation from the disk.
How can I do this? (After the jar file chosen restarting an application also accepted)
I realy like your approach, unfortunately spring has lifecycles that are strict. As you might know, spring autowires "beans" only. Exactly one lifecycle registers the different bean candidates. After that lifecycle spring (by default) does not accept new classes.
You must use the spring-osgi.
If you only need the CDI part out of spring, you might like to use a different CDI like red hat's jboss server.
One of the main advantage of using spring dependency injection is for testing the functionality using same interface with different implementation without making any changes in the code, that is through injecting these different implementations(dependencies) in configuration file.
Lets take an example where we have developed our application with java configuration/annotation based (No .xml files at all).
We have done a code freeze and have deployed the code in server.
Now for a QA team to perform testing they need to inject different implementations for the interface by making changes in configuration file without touching code.
If its a .xml file, devOps team can inject the different implementation by injecting that bean name and can restart the server.
But since we have used the annotations based/java based configuration, How can we achieve this ?
Thanks in advance.
One of the main advantage of using spring dependency injection is for
testing the functionality using same interface with different
implementation
One of main advantages of Spring is indeed the dependency injection facility.
But you will also find very often cases where you have beans with a single implementation :
beans that rely on an interface but there is only one implementation for it.
bean that don't rely on any interface but are straight classes that you want to turn into injectable beans.
We have done a code freeze and have deployed the code in server. Now
for a QA team to perform testing they need to inject different
implementations for the interface by making changes in configuration
file without touching code.
Spring and more generally dependency injection pattern/frameworks are not designed to perform hot swapping or implementation modification of a deployed component without repackaging the component.
At startup, Spring creates its context and loads all required beans for the application in its container.
If you want to change configurations of some beans, the most clean and side effect less way is destroying the spring context/container, repackage the application with the needed changes and restart it.
If its a .xml file, QA team can inject the different implementation by
injecting that bean name and can restart the server.
Ideally, the QA team should test the implementation that you deploy in QA env and that will be used by final users to stay the closest of the real functioning of the application.
Now, if because of some specific constraints, some components to test by the QA should be mocked/stubbed in a some way, just create a different build for that.
Spring Boot Profile and Maven Profile features can help for.
I am new to spring-boot. I am building a rest based application using spring-boot and was working on setting up security using spring-security. It is my understnading that I can setup spring-security with either xml config or with Java config.
However, I found the following in spring-boot documentation. https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-configuration-classes.html
It is in favor of using Java Config as opposed to XML config. Changes in Java config requires recompilation. Yet, it makes me think why the documentation favors Java Config.
Configuration classes Spring Boot favors Java-based configuration. Although it is possible to call SpringApplication.run() with an XML
source, we generally recommend that your primary source is a
#Configuration class. Usually the class that defines the main method
is also a good candidate as the primary #Configuration.
Many Spring configuration examples have been published on the Internet
that use XML configuration. Always try to use the equivalent
Java-based configuration if possible. Searching for Enable*
annotations can be a good starting point.
15.1 Importing additional configuration classes You don’t need to put all your #Configuration into a single class. The #Import annotation
can be used to import additional configuration classes. Alternatively,
you can use #ComponentScan to automatically pick up all Spring
components, including #Configuration classes.
15.2 Importing XML configuration If you absolutely must use XML based configuration, we recommend that you still start with a #Configuration
class. You can then use an additional #ImportResource annotation to
load XML configuration files.
There are some advantages
Java is type safe. Compiler will report issues if you are configuring right bean class qualifiers.
XML based on configuration can quickly grow big. [Yes we can split and import but still
Search is much simpler, refactoring will be bliss. Finding a bean definition will be far easier.
There are still people who like XML configuration and continue to do it.
For more info you can refer Java configuration advantages Some more reasons
I am creating web service. I have application tier and web tier. Both of this tier using jaxb to generate object factory from xsd. Generating class are in package: my.package.v1
Now I have another project which has dependency on these project.
In context I have specify object factory:
<bean id="objectFactory" class="my.package.v1.ObjectFactory" />
when I compile and deploy application everything is OK. But there is two Object factory and he can use just one of them. Which one application use and how I change it and use another one ?
UPDATE:
Is there options how to set in spring context which class to use ?
I want change this to set right class when I have two ObjectFactory
<bean id="objectFactory" class="my.package.v1.ObjectFactory" />
There can be conflicting results and depends on Contextual classloader. I would suggest to have them in separate packages to avoid namespace conflicts
Which one of the two implementations of my.package.v1.ObjectFactory that is actually used depends on the ClassLoader.
See this question for info on how ClassLoaders resolve this kind of issue.
I'm new to Spring and got a situation that single project with multiple modules including one web module. Web module uses Spring MVC, but I was wondering if I can have main Spring configuration at project level that takes care of whole project, so that I can take full advantages of Spring framework.
main
-module1
-module2
-web
+spring3.1, spring-security
What would be the best setting for this case?
We have this kind of architecture where I work. We decided to use the ContextLoaderListener (Spring Event Listener) in the web module.
Then, in the serverApplicationContext.xml, we import all the modules context files :
<import resource="classpath*:module1ApplicationContext.xml" />
<import resource="classpath*:module2ApplicationContext.xml" />
...
Thus you leverage the spring context loading during the web application context initialization.
The build layout and runtime CLASSPATH are two different things. Even if you define separate applicationContext.xml files or #Configuration classes in different modules, they might get merged into a single CLASSPATH.
That being said module1 and module2 might declare their own contexts, but since the CLASSPATH is merged at runtime, only a single main context will be created. Also if you choose to use CLASSPATH scanning in one module, it might pick-up classes (beans) annotated with #Service in other modules.
In web module, which should also have dependencies on Spring core libraries, will also depend on spring-web, MVC and spring-security. This module will create child web context, that has access to main context but not the other way around.
Obviously you should have only a single copy of each library in your uber-JAR (ear?)