Spring中Template模式与callback的结合使用浅析

Spring不论是与ibatis,还是与Hibernate的结合中,都使用到了Template模式与callback技术,来达到简化代码实现的目的。Template模式也即模板模式,用于对一些不太变化的流程进行模板化,与callback结合,可以将变化的部分出离出来,使用callback实现。然后根据不同的情况,向template注入不同的callback。那些模板代码就没有必要重复写了。我们看下spring和ibatis的结合中,Template和callback的使用:

public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {
    // ... ...
    /**
     * Execute the given data access action on a SqlMapExecutor.
     * @param action callback object that specifies the data access action
     * @return a result object returned by the action, or <code>null</code>
     * @throws DataAccessException in case of SQL Maps errors
     */
    public <T> T execute(SqlMapClientCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");

        // We always need to use a SqlMapSession, as we need to pass a Spring-managed
        // Connection (potentially transactional) in. This shouldn‘t be necessary if
        // we run against a TransactionAwareDataSourceProxy underneath, but unfortunately
        // we still need it to make iBATIS batch execution work properly: If iBATIS
        // doesn‘t recognize an existing transaction, it automatically executes the
        // batch for every single statement...

        SqlMapSession session = this.sqlMapClient.openSession();
        if (logger.isDebugEnabled()) {
            logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
        }
        Connection ibatisCon = null;

        try {
            Connection springCon = null;
            DataSource dataSource = getDataSource();
            boolean transactionAware = (dataSource instanceof TransactionAwareDataSourceProxy);

            // Obtain JDBC Connection to operate on...
            try {
                ibatisCon = session.getCurrentConnection();
                if (ibatisCon == null) {
                    springCon = (transactionAware ?
                            dataSource.getConnection() : DataSourceUtils.doGetConnection(dataSource));
                    session.setUserConnection(springCon);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
                    }
                }
                else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
                    }
                }
            }
            catch (SQLException ex) {
                throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
            }

            // Execute given callback...
            try {
                return action.doInSqlMapClient(session);
            }
            catch (SQLException ex) {
                throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
            }
            finally {
                try {
                    if (springCon != null) {
                        if (transactionAware) {
                            springCon.close();
                        }
                        else {
                            DataSourceUtils.doReleaseConnection(springCon, dataSource);
                        }
                    }
                }
                catch (Throwable ex) {
                    logger.debug("Could not close JDBC Connection", ex);
                }
            }

            // Processing finished - potentially session still to be closed.
        }
        finally {
            // Only close SqlMapSession if we know we‘ve actually opened it
            // at the present level.
            if (ibatisCon == null) {
                session.close();
            }
        }
    }
public <T> T execute(SqlMapClientCallback<T> action) throws DataAccessException该方法就是一个模板方法,方法的参数是一个回调对象。在模板方法中,将一些相同的处理过程模板化,比如获得数据库连接,处理事务,处理异常,关闭资源等等,这些都是每一个sql执行时都要面临的相同的过程,所以我们将他们房子模板方法中。然后将不同的部分通过 callback 对象作为参数传入进去,这样将模板代码和非模板代码进行了隔离。没有必要将模板代码每次都写一遍。
    public Object queryForObject(final String statementName, final Object parameterObject)
            throws DataAccessException {

        return execute(new SqlMapClientCallback<Object>() {
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForObject(statementName, parameterObject);
            }
        });
    }

    public List queryForList(final String statementName, final Object parameterObject)
            throws DataAccessException {

        return execute(new SqlMapClientCallback<List>() {
            public List doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForList(statementName, parameterObject);
            }
        });
    }

    public Map queryForMap(
            final String statementName, final Object parameterObject, final String keyProperty)
            throws DataAccessException {

        return execute(new SqlMapClientCallback<Map>() {
            public Map doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                return executor.queryForMap(statementName, parameterObject, keyProperty);
            }
        });
    }

我们看一下上面这些方法,都是借助模板方法来处理那些每次都相同的流程,然后传入一个自己实现的 callback 对象。模板会自动回调我们在 callback 对象中定义的方法。

我们看下JdbcTemplate中的模板方法也是相似的:

    public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");

        Connection con = DataSourceUtils.getConnection(getDataSource());
        try {
            Connection conToUse = con;
            if (this.nativeJdbcExtractor != null) {
                // Extract native JDBC Connection, castable to OracleConnection or the like.
                conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
            }
            else {
                // Create close-suppressing Connection proxy, also preparing returned Statements.
                conToUse = createConnectionProxy(con);
            }
            return action.doInConnection(conToUse);
        }
        catch (SQLException ex) {
            // Release Connection early, to avoid potential connection pool deadlock
            // in the case when the exception translator hasn‘t been initialized yet.
            DataSourceUtils.releaseConnection(con, getDataSource());
            con = null;
            throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);
        }
        finally {
            DataSourceUtils.releaseConnection(con, getDataSource());
        }
    }
时间: 2024-11-05 20:32:10

Spring中Template模式与callback的结合使用浅析的相关文章

spring 中单利模式的理解

一.Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方. 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求多对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对该单列状态的修改(体现为该单列的成员属性),则必须考虑线程同步问题

spring中策略模式使用

策略模式 工作中经常使用到策略模式+工厂模式,实现一个接口多种实现的灵活调用与后续代码的扩展性.在spring中使用策略模式更为简单,所有的bean均为spring容器管理,只需获取该接口的所有实现类即可. 下面以事件处理功能为例,接收到事件之后,根据事件类型调用不同的实现接口去处理.如需新增事件,只需扩展实现类即可,无需改动之前的代码.这样即做到了功能的隔离,又可防止改动原代码导致的bug. 类图 代码示例 定义接口 public interface IBaseEventService { /

Spring 中 Singleton 模式的线程安全

Spring 中管理的 Bean 实例默认情况下是单例的(sigleton 类型),但 Spring 中的单例并不会影响应用的并发访问. E.g. 从客户端传递到后台 controller - Service - Dao 这一个流程中,它们这些对象都是单例的,那么这些单例的对象在传递实体 bean 时不会出问题么? 由于实体 bean 不是单例的,并没有交给 Spring 来管理,每次都是手动的 New 出来的,所以即使那些处理数据的业务处理类是被多线程共享的,但是它们处理的数据并不是共享的,数

9种设计模式在Spring中的运用,一定要非常熟练

1.简单工厂(非23种设计模式中的一种) 实现方式: BeanFactory.Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定. 实质: 由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类. 实现原理: bean容器的启动阶段: 读取bean的xml配置文件,将bean元素分别转换成一个BeanDefinition对象. 然后通过BeanDefinitionRegistr

Spring中的设计模式

[Spring中的设计模式] http://www.uml.org.cn/j2ee/201301074.asp [详解设计模式在Spring中的应用] [http://www.geek521.com/?p=6883] [http://blog.csdn.net/fg2006/article/details/6435410] [http://ylsun1113.iteye.com/blog/828542 ] 1.简单工厂  又叫做静态工厂方法(StaticFactory Method)模式,但不属

详解设计模式在Spring中的应用

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆. 今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的思想理念,才能在工作学习中运用到“无形”. Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范.好了,话不多说,开始今天的内容. spring中常用的设计模式达到九种,我们一一举例: 第一种:简单工厂 又叫做静态工厂方法(StaticFactory Me

Spring中的用到的设计模式大全

spring中常用的设计模式达到九种,我们举例说明: 第一种:简单工厂 又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一. 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类. spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定.如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean.

Spring中应用的那些设计模式

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆. 今天,我们就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的思想理念,才能在工作学习中运用到“无形”. Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范.Spring中常用的设计模式达到九种,如下: 第一种:简单工厂 又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一. 简单工

Spring中如何使用工厂模式实现程序解耦?

目录 1. 啥是耦合.解耦? 2. jdbc程序进行解耦 3.传统dao.service.controller的程序耦合性 4.使用工厂模式实现解耦 5.工厂模式改进 6.结语 @ 1. 啥是耦合.解耦? 既然是程序解耦,那我们必须要先知道啥是耦合,耦合简单来说就是程序的依赖关系,而依赖关系则主要包括 1. 类之间的依赖 2. 方法间的依赖 比如下面这段代码: public class A{ public int i; } public class B{ public void put(A a)