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?)
Related
I have set up my project in multiple modules based on the Spring framework. Currently there is only one runnable application combining all those modules.
Some of the modules provide functionality that might be reusable by other projects (or at least I could imagine reusing them in an other project). Some (but not all) modules also provide s spring Configuration. However when trying to create an application based on that configuration alone, requires defining many beans on top. This suggests that the configuration at that level does not make much sense, as there are dependencies on the level of Maven, which are not reflected in the Spring configuration.
As I am moving toward Spring Boot does this set up make sense or should the beans be defined at the level, where the configuration dependencies and Maven dependencies do match?
I'd like to define some commonly used or generic service classes that should be used/shared by different projects. These common services should already make use of #Transactional, #Autowired and other Spring related stuff. So, I somehow have to define a spring context for these services to work.
Is it possible to put these services in a single external jar library that can then be used/imported by other (child)-projects? How could I create such a "personal framework"?
What you could do is create a maven (or gradle) module that contains the code you desire to be reusable and also have a spring configuration (either XML or Java Config) that will be imported by the project that uses the module (either with or having component scanning pick up the #Configuration class of the module).
I am creating an application where I have separated the project in different modules such as (domain, repository, service and web) as well as many general purpose maven projects for mail sending, text formatting etc. I am also using Spring.
Currently I have the Spring application context file only in the web project. However, since I am creating general pupose projects for text formatting etc that encapsulates libraries (e.g. freemarker) from the actual application I don't like that I have to specify library dependent configuration in the Spring application context file in the web project.
The question is whether or not it is correct to have a separate Spring applicaiton context file for each module and then import the context files in the projects where I use them. Is this the correct way to do it, or are there better ways?
I am interested in how to solve this when I use XML files, not JavaConfig.
Create applicationContext.xml configuration for all modules and place it in modules, then from web module imports all configuration from all modules.
web.xml
<!-- Context Configuration locations for Spring XML files -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/applicationContext-resources.xml
classpath:/applicationContext-dao.xml
classpath:/applicationContext-service.xml
classpath*:/applicationContext.xml
/WEB-INF/applicationContext*.xml
/WEB-INF/cxf-servlet.xml
/WEB-INF/security.xml
</param-value>
</context-param>
In this example all applicationContext.xml are imported from modules.
This example code is copyied from AppFuse application, take look on how this application is configured. To build sample multimodule Spring application with AppFuse use:
mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-spring-archetype -DarchetypeVersion=3.0.0 -DgroupId=com.mycompany -DartifactId=myproject -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse
References:
Splitting applicationContext to multiple files
Appfuse Quickstart
I second Boris the Spider's comment about annotation based config.
My solution to the problem is first to use annotation based configuration in modules (and everywhere).
The second step is to configure the parent project to component scan the packages of the modules.
Finally if something is not completely handled by the annotations, it is most likely something that needs careful configuration to work inside the parent anyway.
Here is a newer reference on the annotation based configuration. Most cases can be handled with one or two simple annotations. Check out #Value that can be used to set values from properties etc.
My spring mvc application is broken into modules.
My services are in their own module.
Previously I used to put a #Service annotation on my services, but since they are in a seperate module, that doesn't have spring, how can I wire them up automatically like before in my web application?
If you split application into modules you have split its dependencies too.
For example:
Your ui depends on spring-mvc.
Your services depend on spring-core and hibernate-annotation.
Your services-impl depend on hibernate-core.
And then if your modeles have appropriate dependence. You can use #Service as you used.
Please bear in mind that when you create WAR with your application, all required modules will be placed in WEB-INF/lib along with Spring dependencies (required by MVC module).
So module in which your services are placed may have dependency to spring-context (containing annotations) since the MVC module requires this dependency itself so it will be placed in the final package anyway. If you use maven, it will handle everything under the hood automatically.
However, if you don't want to have dependencies to spring, because, for example, your 'services module' is deployed as a separate, spring-free bundle, you can use JSR330 #Inject, #Resource and #Qualifier Java annotations - these works interchangeable to Spring equivalents. However I don't know Java equivalents of #Service, #Component or #Repository, so in these cases you can rely on XML Spring context configuration in your MVC module.
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.