Spring模板模式(Template+Callback)

之前在看《Spring揭秘》的时候,发现了Spring处理数据库的精髓类JdbcTemplate,它使用了模板的设计模式,即将流程固定化,比如数据库连接的获取,数据库连接的关闭等,然后将变化的部分交由子类或者回调函数实现。
以前接触的都是抽象父类声明流程,流程中包含抽象函数,子类继承父类并实现父类的抽象函数,这样父类的流程这个流程是不变的,变的只是子类的抽象方法的实现。但是这个的基础是继承,如果你变化的部分太多,你要实现很多很多类,而且如果父类的流程有多个,那子类要实现自己并不需要的抽象函数,这是一个弊端。
Spring在几个*Template的类中使用回调函数的方式,比如下面是JdbcTemplate的方法:
 

 public <T> T execute(StatementCallback<T> action) throws DataAccessException {
        Assert.notNull(action, "Callback object must not be null");
        Connection con = DataSourceUtils.getConnection(this.getDataSource());
        Statement stmt = null;

        Object var7;
        try {
            Connection conToUse = con;
            if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
                conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
            }

            stmt = conToUse.createStatement();
            this.applyStatementSettings(stmt);
            Statement stmtToUse = stmt;
            if (this.nativeJdbcExtractor != null) {
                stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
            }

            T result = action.doInStatement(stmtToUse);
            this.handleWarnings(stmt);
            var7 = result;
        } catch (SQLException var11) {
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            DataSourceUtils.releaseConnection(con, this.getDataSource());
            con = null;
            throw this.getExceptionTranslator().translate("StatementCallback", getSql(action), var11);
        } finally {
            JdbcUtils.closeStatement(stmt);
            DataSourceUtils.releaseConnection(con, this.getDataSource());
        }

        return var7;
    }


可以发现,它的参数是StatementCallback<T> action,以CallBack结尾,可以看到这是个接口,接口定义了一个方法,这个方法就是被流程调用的:

package org.springframework.jdbc.core;

import java.sql.SQLException;
import java.sql.Statement;
import org.springframework.dao.DataAccessException;

public interface StatementCallback<T> {
    T doInStatement(Statement var1) throws SQLException, DataAccessException;
}

只要继承并实现自己的需要实现的方法就可以了,这样在多个流程的情况下,你不需要实现自己不需要的方法。
除此之外,还发现了两个类似的类:事务处理的TransactionTemplate以及处理redis的RedisTemplate,都使用了类似的方式。比如前者:

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
            return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
        } else {
            TransactionStatus status = this.transactionManager.getTransaction(this);

            Object result;
            try {
                result = action.doInTransaction(status);
            } catch (RuntimeException var5) {
                this.rollbackOnException(status, var5);
                throw var5;
            } catch (Error var6) {
                this.rollbackOnException(status, var6);
                throw var6;
            } catch (Throwable var7) {
                this.rollbackOnException(status, var7);
                throw new UndeclaredThrowableException(var7, "TransactionCallback threw undeclared checked exception");
            }

            this.transactionManager.commit(status);
            return result;
        }
    }


 

package org.springframework.transaction.support;

import org.springframework.transaction.TransactionStatus;

public interface TransactionCallback<T> {
    T doInTransaction(TransactionStatus var1);
}

它的实现类:

package org.springframework.transaction.support;

import org.springframework.transaction.TransactionStatus;

public abstract class TransactionCallbackWithoutResult implements TransactionCallback<Object> {
    public TransactionCallbackWithoutResult() {
    }

    public final Object doInTransaction(TransactionStatus status) {
        this.doInTransactionWithoutResult(status);
        return null;
    }

    protected abstract void doInTransactionWithoutResult(TransactionStatus var1);
}



下面是调用的一个代码片段:

int propagation = newTxRequired ? 3 : 0;
TransactionAttribute transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(testContext, new DefaultTransactionAttribute(propagation));
(new TransactionTemplate(transactionManager, transactionAttribute)).execute(new TransactionCallbackWithoutResult() {
   public void doInTransactionWithoutResult(TransactionStatus status) {
             populator.execute(dataSource);
   }
 });

使用匿名内部类,不过这些CallBack类大部分都是函数式接口,以后可以使用Lambda表达式来实现。

补充,又发现一个类似的:
在spring-jms中的JmsTemplate以及其中的eecute方法,在查看*Callback的接口时,如果你想查看它的具体实现,大部分是匿名内部类,比如SessionCallback:

这1,2…都是匿名内部类,比如:

public <T> T execute(final Destination destination, final ProducerCallback<T> action) throws JmsException {
        Assert.notNull(action, "Callback object must not be null");
        return this.execute(new SessionCallback<T>() {
            public T doInJms(Session session) throws JMSException {
                MessageProducer producer = JmsTemplate.this.createProducer(session, destination);

                Object var3;
                try {
                    var3 = action.doInJms(session, producer);
                } finally {
                    JmsUtils.closeMessageProducer(producer);
                }

                return var3;
            }
        }, false);
    }
————————————————
版权声明:本文为CSDN博主「幺零小柒」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a_842297171/article/details/81746307

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值