Have been assigned to re-assess a Spring 4 MVC Rest app where previous developers
where placing the loading of the configuration properties inside the following places:
WEB-INF/mvc-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<import resource="classpath:mydatabase.xml" />
<context:component-scan base-package="com.myapp.rest, com.myapp.config" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<util:properties id="props" location="classpath:prop.properties" />
</beans>
src/main/resources/mydatabase.xml:
<bean id="propertyPlaceholder"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="location" value="file:/opt/database.properties">
</property>
<bean id="mydatabase" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${db.driver}</value></property>
<property name="url"><value>${db.url}</value></property>
<property name="username"><value>${db.username}</value></property>
<property name="password"><value>${db.password}</value></property>
<property name="maxIdle" value="10" />
<property name="maxActive" value="50" />
<property name="maxWait" value="100" />
<property name="defaultAutoCommit" value="false" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="1" />
<property name="minIdle" value="0"></property>
<property name="timeBetweenEvictionRunsMillis" value="1000"></property>
<property name="minEvictableIdleTimeMillis" value="1000"></property>
</bean>
src/main/resources/prop.properties:
banner = images/banner.png
Inside the code, I've been seeing people use the follow way to insert the banner file location:
private #Value("#{props[banner]}") String banner;
My objective is to add a new properties file:
src/main/resources/config.properties
So, I can use the #Value annotation...
Question(s):
What's the BEST way to reorganize some of these config files?
Where would I declare this new config.properties file and what is the declaration?
Put the property files in src/main/resources.
2.
#Configuration
#PropertySource("classpath:config.properties")
public class PropertiesWithJavaConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If you want to load multiple files, use PropertySources
PropertyPlaceholderConfigurer is deprecated in favor of PropertySourcesPlaceholderConfigurer for years now. I hope you'll ditch the XML and move to JavaConfig for, if not anything else, type safety.
Related
I'm trying to add css to my spring web app.
According to guides proper way to do that is to add some code in spring.xml:
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
But i receive error: Can't resolve location /'resources/
spring.xml file:
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/tool
http://www.springframework.org/schema/tool/spring-tool.xsd">
<!-- Step 3: Add support for component scanning -->
<context:component-scan base-package="com" />
<!-- Step 4: Add support for conversion, formatting and validation support -->
<!-- Step 5: Define Spring MVC view resolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/hb_student_tracker?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="hbstudent"/>
<property name="password" value="hbstudent"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="com.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="myTransactionalManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="myTransactionalManager"/>
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
</beans>
Finally, somehow i've found solution:
That's how path to files look: web/resources/css/
Notice, that folder resources is a regular folder that's not marked as "Resource folder"
spring.xml contains following:
<mvc:resources mapping="/resources/**" location="/resources/"/>
I've created the "model" app which works with database(Spring+Hibernate), it works fine when I launch it for testing with main() method:
ApplicationContext applicationContext =
new FileSystemXmlApplicationContext("src/main/resources/META-INF/spring/ApplicationContext.xml");
CityService service =
(CityService) applicationContext.getBean("cityService");
//all other methods
But when I build that app into the .jar file and include it in my Spring MVC webapp as dependency and trying to use CityService inside a controller, it throws an exception:
org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class 'org.hibernate.dialect.MySQLDialect' for connect URL 'jdbc:mysql://localhost:3306/delivery'
...
java.sql.SQLException: No suitable driver
When building "model" app into .jar I commented testing beans:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:property-placeholder location="classpath*:META-INF/spring/*.properties" />
<context:spring-configured />
<context:component-scan base-package="com.userok.pet.delivery.model">
<context:exclude-filter expression=".*_Roo_.*"
type="regex" />
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.username}" />
<property name="password" value="${database.password}" />
<property name="testOnBorrow" value="true" />
<property name="testOnReturn" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="1800000" />
<property name="numTestsPerEvictionRun" value="3" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!--beans used for testing-->
<!--<bean class="com.userok.pet.delivery.model.service.CargoService"
id="packageService"/>
<bean class="com.userok.pet.delivery.model.dao.CargoDAO"
id="packageDao"/>
<bean class="com.userok.pet.delivery.model.service.CityService"
id="cityService"/>
<bean class="com.userok.pet.delivery.model.dao.CityDAO"
id="cityDao"/>
-->
<tx:annotation-driven
transaction-manager="transactionManager" />
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit" />
<property name="dataSource" ref="dataSource" />
</bean>
I wonder why this happens since model app worked properly.
You should have this property defined somewhere "database.driverClassName". Make sure it's set to "com.mysql.jdbc.Driver".
Or just edit the bean org.apache.commons.dbcp.BasicDataSource and change the property "driverClassName" to "com.mysql.jdbc.Driver". Not elegant, but it should get you started.
I have a simple properties file at WEB-INF/local.db.properties:
db.driverClassName=org.postgresql.Driver
db.url=jdbc:postgresql://localhost:5432/db_name
db.username=postgres
db.password=password
I am trying to access these properties inside of my Spring configuration file (towards the end):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="controllers" />
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles-config.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
</bean>
<util:properties id="dbProperties" location="WEB-INF/local.db.properties" />
<bean id="dbDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driverClassName}" /> <!--ERROR -->
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
</beans>
The error is Could not load JDBC driver class [${db.driverClassName}]. The error is pretty clear to me - it is not trying to look up the property it is just using the raw string.
How do I fix this?
This is a Maven 3, Spring 4, Postgresql project.
You're not loading the properties file in Spring configuration. Add this line:
<context:property-placeholder location="classpath:/WEB-INF/local.db.properties"/>
or
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/local.db.properties"/>
</bean>
If you have several properties file, change the above configuration for:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- locations, not location, check the S at the end -->
<property name="locations">
<list>
<value>
/WEB-INF/local.db.properties
</value>
<value>
<!-- Path of another properties file -->
</value>
</list>
</property>
</bean>
More info: PropertySourcesPlaceholderConfigurer
If you are using Eclipse, try right click on project -> Properties -> Java Build Path -> Source, then Add Folder or Link Source to your property files.
We are working on a Spring based Web application where the key to the business is high availability. Hibernate is the ORM and MySQL is the DB that is used. Our architecture forces us to have the following mechanism.
The Webapp first tries to connect to the primary MySQL server.
If that fails, it connects to the Secondary MySQL server, which is mostly out of sync with the data.
The webapp needs to know which MySQL Server it is connected to, since we want to notify the user when he is using the secondary server.
As soon as the connection re-establishes with the primary, the connected has to be switched from secondary to primary.
I am stuck at the very first phase. I am unable find out how to direct Spring/Hibernate to use multiple DB Servers.
Here is the current config file (removing the unwanted stuff):
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan base-package="com.smartshop" />
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/primarydb" />
<property name="username" value="username" />
<property name="password" value="password" />
<property name="maxIdle" value="10" />
<property name="maxActive" value="100" />
<property name="maxWait" value="10000" />
<property name="validationQuery" value="select 1" />
<property name="testOnBorrow" value="false" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="1200000" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>/WEB-INF/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"
name="openSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory"></property>
<property name="flushMode">
<bean
id="org.springframework.orm.hibernate3.HibernateAccessor.FLUSH_AUTO"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
</property>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor" />
<ref bean="openSessionInViewInterceptor" />
</list>
</property>
</bean>
Is there a way to define Spring to connect to a backup datasource when the primary datasource is inaccessible?
if you configure your datasource as a jndi datasource you can use the following configuration
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" ref="datasourceJNDIName" />
<property name="defaultObject" ref="fallBackDataSource" />
</bean>
<!-- fall back datasource if JNDI look up of main datasource fails -->
<bean id="fallBackDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" ref="datasourceJNDIName-2" />
</bean>
This kind of tricks have to be done on MySQL side not on the webapp. MySQL cluster for instance can handle this.
More infos here:
-http://www.mysql.com/products/cluster/
-http://en.wikipedia.org/wiki/MySQL_Cluster
UPDATE:
Ok, so, have a look here -> org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource . Build a custom implementation that override the method getConnection() and getConnection(String username, String password). Surroud them by catching SQLException, and if occurs, choose the other datasource.
I know we can use spring's PropertyPlaceholderConfigurer bean in spring xml file which reads specified properties file and use values in xml file. Like wise is there a way where we can use this mechanism in my persistence.xml file.
Can i use org.eclipse.persistence.jpa.PersistenceProvider in datasource bean like this in spring xml file?
<bean id="dataSource"
class="org.eclipse.persistence.jpa.PersistenceProvider">
<property name="javax.persistence.jdbc.driver" value="${datasource.driverClassName}" />
<property name="javax.persistence.jdbc.url" value="${datasource.url}" />
<property name="javax.persistence.jdbc.user" value="${datasource.username}" />
<property name="javax.persistence.jdbc.password" value="${datasource.password}" />
</bean>
<bean id="entityManager"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="JPAService"/>
<property name="dataSource" ref="dataSource"/>
</bean>
Thanks in Advance.
Like I said in my comment, the first part is not possible, check this SO question
Concerning the second part: yes, that'll work. We use a separate datasource.xml file though and import it into the application context for better modularity.
spring-context.xml:
<import resource="classpath:datasouce.xml" />
datasource.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName">
<bean id="myDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="username" value="..." />
<property name="password" value="..." />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/myTestDB" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDatasource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
</beans>
Rather than using your build to create a prod or dev version of your persistence.xml, just move all property settings to your spring content.
read the original post by emeraldjava loading .properties in spring-context.xml and persistence.xml