we have quite a few projects that use the same codebase (backend code).
Just the frontend tends to be different.
We decided that the best approach would be to seperate backend and frontend into different projects: Engine and Project_name
Now these are Spring-projects. So it would only seem logical if we divide the Spring configurations aswell:
Database.xml, Services.xml would belong to the project Engine.
And a specific Frontend.xml would belong to Project_Name.
To link these up, I would need a generic SpringBeans.xml that imports all of these XML's.
I tried following directory structure:
Engine Project
Config
Spring
Database.xml
Services.xml
Project_Name Project
Config
SpringBeans.xml
spring
Frontend.xml
The contents of SpringBeans.xml are simply:
<import resource="spring/Database.xml"/>
<import resource="spring/Services.xml"/>
<import resource="spring/Frontend.xml"/>
I set up Eclipse so the Project_Name project references the Engine project.
When I start it, SpringBeans.xml gets found, however the XML files in the Engine project aren't found (FileNotFoundException).
I'll also note that before splitting up the Engine and Frontend code into different projects, the principle of importing other XML files worked like a charm.
So my question to you: Is it possible to make different Spring configrations in different projects play together nicely?
Since the spring bean configuration files are in the classpath, you need to add the prefix claspath to the resource location:
<import resource="classpath:spring/Database.xml"/>
<import resource="classpath:spring/Services.xml"/>
<import resource="classpath:spring/Frontend.xml"/>
Related
I'm having a problem properly setting up spring boot for my multi-module maven project.
There is a module "api" that uses another module "core". Api has an application.properties file that contains spring.mail.host=xxx. According to the spring boot documentation this provides you with a default implementation of the JavaMailSender interface, ready to be autowired.
However the class that is responsible for sending out the e-mails resides in the "core" package. When I try to build that module the build fails because no implementation of JavaMailSender can be found.
My guess then was that the mailing config should reside in "core" in a separate application.properties. I created that and moved the spring.mail.host property from the "api" to the "core" property file.
This time the core module builds successfully, but "api" fails to build because of the same exception, so I think I just moved the problem.
I don't understand the required structure for handling this type of situations well enough so I was wondering what the correct way is for having a "core" module containing all the correct configuration for sending mails and having other modules use the mailing code and config that resides in it.
I found the answer in another stack overflow question: How to add multiple application.properties files in spring-boot?
It turns out there can only be 1 application.properties file in the final jar that spring boot creates. To have multiple files you have to rename one of the files to something custom. I named the properties of the core module "core-application.properties".
Then in the API module I added this to the spring boot application class:
#SpringBootApplication
#PropertySource(value = {"core-application.properties", "application.properties"})
Doing this I can correctly use the base properties file and overwrite them in the more specific modules. Also you can still create profile-specific properties file (core-application-production.properties) with this setup, no need to add those to the propertysource manually). Note that #PropertySource does not work for yaml configuration files at this moment.
there is one effective application.properties per project. you just keep 2 properties file for a success build.
when api module use core module, the application.properties in core module is overwrite by api.
Your API's pom.xml must has dependency of CORE module.
the solution is to define properties files as a value of #PropertiesSource in Starter class.
but it is beter to put "classpath:" behind the properties files.
for example in Intellij idea after adding the "classpatch:" word berhind the files name, values become to link. like this:
#SpringBootApplication
#PropertySource(value = {"classpath:core-application.properties", "classpath:application.properties"})
I hope to helped you.
I am trying to come up with a solution for managing XML configuration files for multi-environment builds that does not involve maintaining one configuration file for each environment. By XML configuration file, I mean XML files used at run-time, ie web.xml, and not the POM itself. I could of course maintain a separate XML file for each environment and then define a Maven property that contains the different file path and then have separate Maven profiles that point to the correct file path for the profile to correctly package them into the WAR/EAR/etc based upon environment, but I would prefer a different solution.
Like I am suggesting in the title, the differences are not something that can be accomplished by a simple token replacement - completely different XML structures are required in different environments. I originally tried using the maven Antrun plugin to run Ant's xmltask to add/remove/delete nodes via Xpath, but this is overly verbose and complicated to maintain, especially considering this plugin's inability to properly handle XML namespaces in a non-verbose manner.
Ideally, the XML file would like a normal template file, ie:
<x:if environment="production">
<a b="c">
<d>
</a>
</x:if>
<x:else>
<g />
</x:else>
At build time, ie during package or process-resources phases, the resultant XML file would contain only one set of XML or the other (in this example).
Note how, like I mentioned above, the node structures are completely different between environments.
Any ideas or suggestions?
There is "bean definition profiles".
Basic usage:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="businessService"
class="com.c...s.springthreeone.business.SimpleBusinessServiceImpl"/>
<beans profile="dev,qa">
<bean id="constructorBean"
class="com.gordondickens.springthreeone.SimpleBean"
c:myString="Constructor Set"/>
<bean id="setterBean"
class="com.gordondickens.springthreeone.SimpleBean">
<property name="myString" value="Setter Set"/>
</bean>
</beans>
<beans profile="prod">
<bean id="setterBean"
class="com.gordondickens.springthreeone.SimpleBean">
<property name="myString" value="Setter Set - in Production YO!"/>
</bean>
</beans>
</beans>
Add to your WEB.XML for selecting active:
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>prod</param-value>
</context-param>
Or jUnit Tests:
#ActiveProfiles(profiles = "dev")
Or you could set Environment Variable/JVM Parameter:
SPRING_PROFILES_DEFAULT=dev
Oryou could set selected profile with maven:
mvn -DSPRING_PROFILES_DEFAULT=dev
You can create basic maven project with common stuff and create two projects with different web.xml and other files.
Use maven web-app overlays function to marge resources, in that case you will have one project with common files and two other projects - each for required env.
You could even make these projects as modules of another project and run required depending on maven profile.
Goal:
List item
I have a spring webapp project, which is using component scan for configuration and autowiring interface implementation through maven submodules
the main project is dependant on the other modules thus the jar's of the submodules are placed in the /WEB-INF/lib folder
the submodules (aka plugins) have common package parent name x.y.z.extension eg. x.y.z.extension.pluginA
the classes in this package are annotated with #Component or #Configuration
in the servlet xml configuration i have placed such component-scan information:
Code:
<context:spring-configured />
<context:component-scan base-package="x.y.z.extension" />
With the mentioned configuration everything is working correctly.
What I would like to achieve:
List item
remove dependency of the main webapp maven module and other modules - the core webapp will be shipped without plugins
create subfolder e.g. "WEB-INF/classes/plugins" in the classpath classes dir
put there the mentioned jar's from submodules (or extract the jar content to eg. WEB-INF/classes/plugins/pluginA) - this could be done during "plugin installation" with webapp restart after new plugin installation
spring automagically should detect annotated classes and load it into the application context (and use not annotated classes in the plugin jar (annotated classes are mainly interface implementation but they are using some not annotated classes in the jar))
and ... of course this does not work The classes are not found.
If it possible to achieve this only using spring ecosystem, or should I take a look into other examples e.g. jspf ?
How can I modify classpath scanning with spring and also keep automatic component scanning ?
thanks !
I am new to Spring and inherited a Spring project that had all the XML configuration in ProjectName/WebContent/WEB-INF/applicationContext.xml. I'm trying to break the configuration into different components so it is easier to substitute things like DataSources and Hibernate configuation when testing.
Here is my file structure:
ProjectName
->WebContent
->WEB-INF
->applicationContext.xml
->spring-datasource.xml
->spring-hibernate-properties.xml
->spring-persistence.xml
->test
->us.mn.k12... (Java pkgs with JUnit tests)
->spring-hsqldb-datasource.xml
->spring-test-bean-locations.xml
->spring-test-hibernate-properties.xml
->src
->us.mn.k12... (Java pkgs with production code)
In WEB-INF/applicationContext.xml, I import the following:
<import resource="spring-datasource.xml"/> <!-- Production datasource -->
<import resource="spring-hibernate-properties.xml"/> <!-- Production hibernate properties -->
<import resource="spring-persistence.xml"/> <!-- DAO's, hibernate .hbm.xml mapping files -->
The application works with the above configuration.
My JUnit tests run using DbUnit and an HSQLDB in-memory database. So my JUnit test references spring-test-bean-locations.xml, which has the following:
<import resource="spring-hsqldb-datasource.xml"/> <!-- HSQLDB datasource for test -->
<import resource="../WebContent/WEB-INF/spring-persistence.xml"/> <!-- Production DAO's, hibernate .hbm.xml mapping files -->
<import resource="spring-test-hibernate-properties.xml"/> <!-- Hibernate properties for test -->
In this way, I can specify test datasource and hibernate properties, but reuse the production mapping file for the DAO's, etc. However, I get an error running my JUnit test. Here is the relevant part of the exception:
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [../WebContent/WEB-INF/spring-persistence.xml]
Offending resource: class path resource [spring-test-bean-locations.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [../WebContent/WEB-INF/spring-persistence.xml]; nested exception is java.io.FileNotFoundException: class path resource [../WebContent/WEB-INF/spring-persistence.xml] cannot be opened because it does not exist
Now if I move spring-persistence.xml into /test so that I don't have to use the relative path, and reference it with <import resource="spring-persistence.xml"/>, then the tests run fine. So I think the contents of my XML files are OK, but I'm not properly importing with a relative path.
Is there anything obvious I'm doing wrong with my import of the relative path? And maybe the bigger question is does this look like a reasonable strategy for breaking applicationContext.xml into components to make it easier for testing?
Thanks!
The problem is: anything inside WEB-INF is not available to the ClassLoader in a regular project setup (and spring uses the ClassLoader by default to access resources). There are some hacks to work around this (like referencing the contexts using the file: prefix), but those are mostly ugly.
A better practice I'd suggest is to move the context files out of WEB-INF and into a dedicated resource directory (src/main/resources if you have a maven setup). That way they will be available to both the webapp ClassLoader and local unit test ClassLoaders.
Read the resources chapter to further understand the mechanisms involved.
Use
<import resource="file:**/WebContent/WEB-INF/spring-persistence.xml" />
It works in spring 3.2.1.RELEASE. Old versions I am not sure.
I have a new web app that is packaged as a WAR as part of a multi-module Maven project. The applicationContext.xml for this WAR references beans that are imported from the "service" module, which in turn imports beans from the "dao" module. The import statement in applicationContext.xml looks like this:
<import resource="classpath*:service.xml" />
and the one inside the service.xml file looks like this:
<import resource="classpath*:dao.xml" />
Neither Spring STS, nor Eclipse show any warnings or errors in my bean files. I reference the imported beans all over the place. The Maven build works fine and the DAO integration tests all pass (they use the beans). I don't have any service integration tests yet.
But when I start up the WAR in Jetty I get an error:
Error creating bean with name 'securityService'
Cannot resolve reference to bean 'userDAO' while setting constructor argument
All of the imported bean XML files can be found inside their respective JAR files in the WEB-INF/lib directory. Indeed, the service bean that threw the error is itself defined inside the service.xml file inside the service module's JAR file.
Apparently the service module can't find the bean that it imported from the dao module. Obviously I don't understand something...seems like this should this Just Work?
I enabled DEBUG logging for 'org.springframework' in order to see if I could learn anything. What I found were messages to the effect that the DAO beans had been created, but there was also a message about them having no name or id.
I check the file, and they all did have an id. So what was it? I check the XML namespace and saw:
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
and noticed it was old (I am using Spring 3.0.2) and changed it to:
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
Once I changed it, Spring instantly threw half a dozen errors regarding beans that were defined incorrectly (but never used apparently). Once I fixed those errors, everything Just Worked. I've since gone through the entire system checking Spring XML file namespace versions.
Thanks to all for the help. Can't believe I wasted a day on this stupidity!!
The difference between the classpath:thingy.xml and classpath*:thingy.xml notation is that the former uses the standard classpath mechanism to resolve one resource (using ClassLoader.getResource(name)), whereas the latter will use ClassLoader.getResources(name) to retrieve all matching resources on the classpath, a distinction that should be irrelevant in your situation as I guess there is only one dao.xml file on the class path.
I think your problem is different, you are missing a leading slash.
Use this for a single resource
<import resource="classpath:/dao.xml" />
and this for multiple resources
<import resource="classpath*:/dao.xml" />
See
Spring Reference: The classpath*
prefix
Sun JavaDocs: ClassLoader
It should be like
<import resource="classpath:service.xml"/>
Are you having multiple applicationContexts and possibly the parent context is referring to a bean defined in the child context?