Spring源代码分析(11)---JDBC Dao(老树发新芽)

来源:互联网 发布:500以内素数c语言程序 编辑:程序博客网 时间:2024/06/10 05:35
在数据库访问技术中,我们有很多选择,诸如jpa,hibernate但是无论选择那种,其实,我们都无法拒绝使用JDBC,Spring为集成JDBC做个很多工作,让我们来看下,这最底层数据库访问技术在春天老树发新芽;

实现,我们来看先,我们如何使用SPRING JDBC的配置和使用:

ApplicationContext.xml:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans
  3.     xmlns="http://www.springframework.org/schema/beans"
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  6. <!--数据源的配置-->   
  7. <bean id="dataSource"
  8.         class="org.apache.commons.dbcp.BasicDataSource">
  9.         <property name="driverClassName"
  10.             value="com.mysql.jdbc.Driver">
  11.         </property>
  12.         <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
  13.         <property name="username" value="root"></property>
  14.     </bean>
  15.     <bean id="sessionFactory"
  16.         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  17.         <property name="dataSource">
  18.             <ref bean="dataSource"></ref>
  19.         </property>
  20.         <property name="hibernateProperties">
  21.             <props>
  22.                 <prop key="hibernate.dialect">
  23.                     org.hibernate.dialect.MySQLDialect
  24.                 </prop>
  25.             </props>
  26.         </property>
  27.     </bean>
  28.    <!--Dao的配置-->
  29.     <bean id="dao" name="dao" class="org.corey.dao.CoreyDao"
  30.         dependency-check="default">
  31.         <property name="dataSource">
  32.             <ref bean="dataSource"></ref>
  33.         </property>
  34.     </bean></beans>
测试:
  1. package org.corey.demo;
  2. import org.corey.dao.CoreyDao;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5. import org.springframework.jdbc.core.JdbcTemplate;
  6. public class Demo {
  7.     public static void main(String[] args) {
  8.         ApplicationContext context = new ClassPathXmlApplicationContext(
  9.                 "applicationContext.xml");
  10.         CoreyDao dao = (CoreyDao)context.getBean("dao");
  11.         JdbcTemplate template=dao.getJdbcTemplate();
  12.         template.execute("insert into customer(name) values('corey')");
  13.         
  14.     }
  15. }
下面,我们来详细的分析一下Spring Dao的代码结构:


其实,在这里,有很大的感觉让我们有桥接模式的影子,但是这里我们首先要注意,在JDbcDaoSupport并没有依赖于一个抽象的Template接口,一方面是因为在Sprin构建过程中,DaoSupport与Template之间是一对一的关系,JdbcDaoSupport就只能对应JdbcTemplate,所以,不会出现Template的动态切换,所以这里并没有依赖抽象编程;
在程序中,任何功能方法,都是由接口定义实现的,所以我们可以看见,简单的JdbcTemplate的数据库访问功能的实现是由JdbcAccessor定义实现,与数据库的交互动作是由JdbcOperations定义的;

而JdbcTemplate与DataSource的依赖是基于抽象和接口的,这是因为系统所采用的连接池本身就是一个变化点,在这里,我们是而已实现用户选择定制的,所以,这里,我们更多的是采用了把组合聚合原则实现;

分析完基本结构以后,我们再来看一下功能代码的实现:

Dao:
  1. public abstract class DaoSupport implements InitializingBean {
  2.     /** Logger available to subclasses */
  3.     protected final Log logger = LogFactory.getLog(getClass());
  4.         
  5.         //在访问器注入以后执行的初始化方法,运用了模板模式;
  6.     public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
  7.         themselves.
  8.         try {
  9.             initDao();
  10.         }
  11.         catch (Exception ex) {
  12.             throw new BeanInitializationException("Initialization of DAO failed: " + ex.getMessage(), ex);
  13.         }
  14.     }
  15.     //模板模式的一个抽象方法;
  16.     protected abstract void checkDaoConfig() throws IllegalArgumentException;
  17.     //初始化Dao,这是模板模式的一个钩子;
  18.     protected void initDao() throws Exception {
  19.     }
  20. }

  1. package org.springframework.jdbc.core.support;
  2. import java.sql.Connection;
  3. import javax.sql.DataSource;
  4. import org.springframework.dao.support.DaoSupport;
  5. import org.springframework.jdbc.CannotGetJdbcConnectionException;
  6. import org.springframework.jdbc.core.JdbcTemplate;
  7. import org.springframework.jdbc.datasource.DataSourceUtils;
  8. import org.springframework.jdbc.support.SQLExceptionTranslator;

  9. public abstract class JdbcDaoSupport extends DaoSupport {
  10.     private JdbcTemplate jdbcTemplate;
  11.     //让注入数据源的时候,自动构造出一个模板属性;
  12.         //在此方法之后,会Dao的检查和自定义初始化;
  13.     public final void setDataSource(DataSource dataSource) {
  14.       this.jdbcTemplate = createJdbcTemplate(dataSource);
  15.        initTemplateConfig();//扩展点;
  16.     }
  17.     //通过注入的数据源,构造出模板
  18.     protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
  19.         return new JdbcTemplate(dataSource);
  20.     }
  21.     /**
  22.      * Return the JDBC DataSource used by this DAO.
  23.      */
  24.     public final DataSource getDataSource() {
  25.         return (this.jdbcTemplate != null ? this.jdbcTemplate.getDataSource() : null);
  26.     }
  27.     //注入模板
  28.     public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
  29.         this.jdbcTemplate = jdbcTemplate;
  30.        initTemplateConfig();//扩展点;
  31.     }
  32.     //得到模板;
  33.     public final JdbcTemplate getJdbcTemplate() {
  34.       return jdbcTemplate;
  35.     }
  36.         
  37.         //判断你时候注入了一个模板或者数据源,如果没有,那么抛出异常
  38.     protected final void checkDaoConfig() {
  39.         if (this.jdbcTemplate == null) {
  40.             throw new IllegalArgumentException("dataSource or jdbcTemplate is required");
  41.         }
  42.     }
  43.     //获取连接;
  44.     protected final Connection getConnection() throws CannotGetJdbcConnectionException {
  45.         return DataSourceUtils.getConnection(getDataSource());
  46.     }
  47.         
  48.         //异常转换;
  49.     protected final SQLExceptionTranslator getExceptionTranslator() {
  50.         return this.jdbcTemplate.getExceptionTranslator();
  51.     }
  52.     //关闭连接;
  53.     protected final void closeConnectionIfNecessary(Connection con) {
  54.         releaseConnection(con);
  55.     }
  56.           
  57.         //释放连接;
  58.     protected final void releaseConnection(Connection con) {
  59.         DataSourceUtils.releaseConnection(con, getDataSource());
  60.     }
  61. }
通过这个方式,我们可见系统给我们保留一个扩展的接口,我们在initDao()方法中能够自定义的进行扩展,在后面,我们会看到具体的实例;

接下来,我们来分析一下JdbcTemplate:
JdbcAccessor利用DataSource来实现数据库的访问,通过DataSource出取得连接,用Spring对连接进行管理,然后,利用这个连接实现curd功能;


我们来看下一个扩展好的功能更强大的NamedParameterJdbcDaoSupport;

  1. public class NamedParameterJdbcDaoSupport extends JdbcDaoSupport {
  2.     
  3.     private NamedParameterJdbcTemplate namedParameterJdbcTemplate;


  4.     //自定义扩展代码
  5.         //将一个普通的模板包装成为一个可命名参数的模板
  6.     protected void initTemplateConfig() {
  7.         this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate());
  8.     }

  9.     //获得改良后的模板;
  10.     public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
  11.       return namedParameterJdbcTemplate;
  12.     }

  13. }
之所以没有抽象出Template接口,在这里也有了良好的体现,我们并不是在JdbcDaoSupport中动态的切换了JdbcTemplate类,而是先生成了一个NamedParameterJdbcDaoSupport类,因为JdbcTemplate无法和NamedParameterJdbcTemplate无法用的方法没有办法共享一个接口来定义(参数和功能不同);
在由JdbcTemplate到NamedParameterJdbcTemplate的过程中间,我们发现功能在其基础上强大了,但是功能还是采用委托的机制实现,我们知道在设计模式中间,动态改变方法的模式有大名鼎鼎的三种
1):装饰模式;
2) :代理模式;
3):适配器模式;
由于前两种模式暴露出的接口都是不变的,而适配器模式就正式现在所急需的;




该模板提供参数映射,能够从Bean属性或者Map中得到相应的参数的名字:

原创粉丝点击