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); }

浙公网安备 33010602011771号