Spring datasource configuration for localhost, development, and production
I'm trying to figure out how my Spring app can determine wh开发者_Go百科ere it is deployed and load the appropriate datasource. We have 3 environments...my local, the development server, and the production server. So far I have 3 properties files called
localhost.datasource.properties
development.datasource.properties
production.datasource.properties
I have them conifgured like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/resources/properties/production.datasource.properties</value>
<value>classpath:/resources/properties/development.datasource.properties</value>
<value>classpath:/resources/properties/localhost.datasource.properties</value>
</list>
</property>
</bean>
<bean id="dataSourceMySQL" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${mysql.jdbc.driver.class.name}"
p:url="${mysql.jdbc.url}"
p:username="${mysql.jdbc.username}"
p:password="${mysql.jdbc.password}" />
</beans>
This works fine when I am on my localhost machine. If I deploy a war file to development it is still reading the localhost properties since it is last in the list and I get an error. What is the best way to implement this?
Thanks
For data sources the easiest way would be to define data sources and let the container manage the connection pooling.
To do so, define a resource reference to the data source in web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
and reference it in spring as such:
<jee:jndi-lookup
id="dataSource"
jndi-name="jdbc/MyDataSource" />
then you can define the data source in the application server, which means you can change the underlying database. In case of websphere, this would be done through the websphere console. In case of tomcat, it would be done through the Context.xml:
<Context>
...
<Resource name="jdbc/MyDataSource" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="javauser" password="javadude"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/javatest"/>
</Context>
That way you only need to change the context to deploy to development, test and production and don't tie your application to a specific database.
Pass a system property to the property placeholder, but include all three files in the WAR:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/resources/properties/${myenv}.datasource.properties</value>
</list>
</property>
</bean>
Have a look here: http://blog.jayway.com/2010/10/21/environment-specific-configuration-of-spring-applications/ You can have a default config in your app, and optionally override it with a file in a predefined place on your file system.
Two solutions
Have one value instead of three with a generic name and in your build configuration provide a flag which properties file should be copied to that path/filename.
Provide the properties as an VM argument while starting the server like -Ddatasource.properties=c:\config\development.datasource.properties and in your XML config file <value>file:///${datasource.properties} </value>
The other answers here have good ideas in them, but I'm answering because my own approach is something of a combination of the three. First, don't reference properties files of multiple environments directly in your Spring XML. Just work from a single file. Then, using a combination of Spring's <context:property-placeholder>
, <jee:jndi-lookup>
, <util:properties>
, and SpEL, you can easily set up a very flexible configuration.
- The
<context:property-placeholder>
gets wired with the output of the<util:properties>
. - The
<util:properties>
uses SpEL to check for a system property with a given name. If available, it uses that as the location of a properties file to load. If not, - Fall back to the
<jee:jndi-lookup>
, which tries to do a JDNI lookup for the location. If that also doesn't find anything, then - Default to a hard-coded classpath location given by the
default-value
attribute of<jee:jndi-lookup>
.
This setup makes it simple to specify a properties file location no matter what environment you're in because of all the options.
I would consider using the Cocoon Spring Configurator, which can be used stand-alone, without the rest of the Cocoon project:
http://cocoon.apache.org/subprojects/configuration/spring-configurator/index.html
I found this blog post really useful to get started:
http://mrhaki.blogspot.com/2009/02/use-spring-configurator-to-support.html
精彩评论