Spring Web App - Simple JDBC Template Advice?
Quick question based on a spring web app i am creating.
How do you go about setting up the context of the application so that you do not need to set the datasource parameters for simpleJDBC all the time and can call getSimpleJDBCTemplate().queryfor.... and it be set up with the datasource.
This is how i currently have it and it seems to go against inversion of control that spring is meant to provide as this is in every dao!
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
DataSource dataSource = (DataSource) ac.getBean("dataSource");
SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
ApplicationContext
<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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:properties.properties"/>
</bean>
<bean id="dataSource" destr开发者_运维知识库oy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<bean name="SimpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg><ref bean="dataSource"/></constructor-arg>
</bean>
<context:annotation-config/>
</beans>
Latest Stack Trace from Tomcat log
13-Jan-2011 20:15:18 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
ptc.jersey.spring
13-Jan-2011 20:15:18 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class ptc.jersey.spring.resources.LoginResource
13-Jan-2011 20:15:18 com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
13-Jan-2011 20:15:19 com.sun.jersey.spi.spring.container.servlet.SpringServlet getContext
INFO: Using default applicationContext
13-Jan-2011 20:15:19 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.4 09/11/2010 10:30 PM'
13-Jan-2011 20:15:21 com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
at ptc.jersey.spring.daoImpl.UserDaoImpl.getUser(UserDaoImpl.java:43)
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:ApplicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>Jersey Spring Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>ptc.jersey.spring</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Spring Web Application</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
</web-app>
Any help would be great Thanks Chris
Why don't you declare the SimpleJdbcTemplate instance as well in the application context file?
For example with these bean declarations
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.gjt.mm.mysql.Driver"/>
<property name="url" value="dburl"/>
<property name="username" value="dbusername"/>
<property name="password" value="password"/>
</bean>
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg><ref bean="dataSource"/></constructor-arg>
</bean>
And in your web.xml to load the application context
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:ApplicationContext.xml</param-value>
</context-param>
Declare the SimpleJdbcTemplate bean in the context:
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
and use it like this:
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
SimpleJdbcTemplate simpleJdbcTemplate = (SimpleJdbcTemplate) ac.getBean("jdbcTemplate");
or in a DAO:
@Autowired
private SimpleJdbcTemplate simpleJdbcTemplate;
It is thread-safe, and therefore reusable.
What I'd recommend is that you declare your DataSource
as bean and also the classes which need it and use dependency injection to introduce the DataSource
to your class. As an example, your bean definition could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="dataSource" class="...">
<!-- your dataSource config here -->
</bean>
<bean id="yourClassThatNeedsDataSource" class="com.stackoverflow.q4684102.Example">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
and the accompanying class
package com.stackoverflow.q4684102;
import javax.jdbc.DataSource;
import org.springframework.jdbc.core.simple.*;
public class Example implements YourDaoInterface {
private SimpleJdbcOperations jdbc;
public void setDataSource(DataSource ds) {
jdbc = new SimpleJdbcTemplate(ds);
}
// your DAO methods here
}
Why do it this way instead of creating a bean out of the SimpleJdbcTemplate itself?
No difference, really - some people like it the other way, some others like it this way - you wan't have a huge XML with loads of bean definitions for intermediate objects if you do it this way, that's for sure. That, of course, is up to you to decide on how you want to design your software.
If you create SimpleJdbcTemplate inside setDataSource then you are creating a template per Dao instance. If you configure as a bean and inject into the Dao, then you can resuse the same template across the Daos - which is recommended, because its threadsafe.
精彩评论