<1>:Lambda表达式在编译期通过字节码增强技术新增一个模板类实现对应的接口类型,这个模板类的所有属性都使用final修饰,模板类由关键字final synthetic修饰。
<2>:封闭类会基于类内的Lambda表达式类型生成private static synthetic修饰的静态方法,该静态方法的方法体就是来源于Lambda方法体,这些静态方法的名称是lambda$封闭类方法名$递增数字。
<3>:Lambda表达式调用最终通过字节码指令invokedynamic,忽略中间过程,最后调用到第<2>步中对应的方法。
限于篇幅问题,这里把Lambda表达式的底层原理做了简单的梳理(这个推导过程仅限于个人理解,依据尚未充分):
<1>:封闭类会基于类内的Lambda表达式类型生成private static synthetic修饰的静态方法,该静态方法的方法体就是来源于Lambda方法体,这些静态方法的名称是lambda$封闭类方法名$递增数字。
<2>:Lambda表达式会通过LambdaMetafactory#metafactory()方法,生成一个对应函数式接口的模板类,模板类的接口方法实现引用了第<1>步中定义的静态方法,同时创建一个调用点ConstantCallSite实例,后面会通过Unsafe#defineAnonymousClass()实例化模板类。。
<3>:调用点ConstantCallSite实例中的方法句柄MethodHandle会根据不同场景选取不同的实现,MethodHandle的子类很多,这里无法一一展开。
<4>:通过invokedynamice指令,基于第<1>步中的模板类实例、第<3>步中的方法句柄以及方法入参进行方法句柄的调用,实际上最终委托到第<1>步中定义的静态方法中执行。
如果想要跟踪Lambda表达式的整个调用生命周期,可以以LambdaMetafactory#metafactory()方法为入口开始DEBUG,调用链路十分庞大,需要有足够的耐心。总的来说就是:Lambda表达式是基于JSR-292引入的动态语言调用包java.lang.invoke和Unsafe#defineAnonymousClass()定义的轻量级模板类实现的,主要用到了invokedynamice字节码指令,关联到方法句柄MethodHandle、调用点CallSite等相对复杂的知识点,这里不再详细展开。
实战 基于JdbcTemplate进行轻量级DAO封装假设订单表的DDL如下:
CREATE TABLE `t_order` ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, edit_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID', order_id VARCHAR(64) NOT NULL COMMENT '订单ID', amount DECIMAL(12, 2) NOT NULL DEFAULT 0 COMMENT '订单金额', INDEX idx_user_id (user_id), UNIQUE uniq_order_id (order_id) ) COMMENT '订单表';下面基于JdbcTemplate封装一个轻量级的OrderDao:
// 辅助接口 @FunctionalInterface public interface PreparedStatementProcessor { void process(PreparedStatement ps) throws SQLException; } @FunctionalInterface public interface ResultSetConverter<T> { T convert(ResultSet resultSet) throws SQLException; } // OrderDao接口 public interface OrderDao { int insertSelective(Order record); int updateSelective(Order record); Order selectOneByOrderId(String orderId); List<Order> selectByUserId(Long userId); } // OrderDao实现 @Repository @RequiredArgsConstructor public class MySqlOrderDao implements OrderDao { private final JdbcTemplate jdbcTemplate; private static final ResultSetConverter<Order> CONVERTER = r -> { Order order = new Order(); order.setId(r.getLong("id")); order.setCreateTime(r.getTimestamp("create_time").toLocalDateTime()); order.setEditTime(r.getTimestamp("edit_time").toLocalDateTime()); order.setUserId(r.getLong("user_id")); order.setAmount(r.getBigDecimal("amount")); order.setOrderId(r.getString("order_id")); return order; }; private static final ResultSetExtractor<List<Order>> MULTI = r -> { List<Order> list = new ArrayList<>(); while (r.next()) { list.add(CONVERTER.convert(r)); } return list; }; private static final ResultSetExtractor<Order> SINGLE = r -> { if (r.next()) { return CONVERTER.convert(r); } return null; }; @Override public int insertSelective(Order record) { List<PreparedStatementProcessor> processors = new ArrayList<>(); StringBuilder sql = new StringBuilder("INSERT INTO t_order("); Cursor cursor = new Cursor(); if (null != record.getId()) { int idx = cursor.add(); sql.append("id,"); processors.add(p -> p.setLong(idx, record.getId())); } if (null != record.getOrderId()) { int idx = cursor.add(); sql.append("order_id,"); processors.add(p -> p.setString(idx, record.getOrderId())); } if (null != record.getUserId()) { int idx = cursor.add(); sql.append("user_id,"); processors.add(p -> p.setLong(idx, record.getUserId())); } if (null != record.getAmount()) { int idx = cursor.add(); sql.append("amount,"); processors.add(p -> p.setBigDecimal(idx, record.getAmount())); } if (null != record.getCreateTime()) { int idx = cursor.add(); sql.append("create_time,"); processors.add(p -> p.setTimestamp(idx, Timestamp.valueOf(record.getCreateTime()))); } if (null != record.getEditTime()) { int idx = cursor.add(); sql.append("edit_time,"); processors.add(p -> p.setTimestamp(idx, Timestamp.valueOf(record.getEditTime()))); } StringBuilder realSql = new StringBuilder(sql.substring(0, sql.lastIndexOf(","))); realSql.append(") VALUES ("); int idx = cursor.idx(); for (int i = 0; i < idx; i++) { if (i != idx - 1) { realSql.append("?,"); } else { realSql.append("?"); } } realSql.append(")"); // 传入主键的情况 if (null != record.getId()) { return jdbcTemplate.update(realSql.toString(), p -> { for (PreparedStatementProcessor processor : processors) { processor.process(p); } }); } else { // 自增主键的情况 KeyHolder keyHolder = new GeneratedKeyHolder(); int count = jdbcTemplate.update(p -> { PreparedStatement ps = p.prepareStatement(realSql.toString(), Statement.RETURN_GENERATED_KEYS); for (PreparedStatementProcessor processor : processors) { processor.process(ps); } return ps; }, keyHolder); record.setId(Objects.requireNonNull(keyHolder.getKey()).longValue()); return count; } } @Override public int updateSelective(Order record) { List<PreparedStatementProcessor> processors = new ArrayList<>(); StringBuilder sql = new StringBuilder("UPDATE t_order SET "); Cursor cursor = new Cursor(); if (null != record.getId()) { int idx = cursor.add(); sql.append("id = ?,"); processors.add(p -> p.setLong(idx, record.getId())); } if (null != record.getOrderId()) { int idx = cursor.add(); sql.append("order_id = ?,"); processors.add(p -> p.setString(idx, record.getOrderId())); } if (null != record.getUserId()) { int idx = cursor.add(); sql.append("user_id = ?,"); processors.add(p -> p.setLong(idx, record.getUserId())); } if (null != record.getAmount()) { int idx = cursor.add(); sql.append("amount = ?,"); processors.add(p -> p.setBigDecimal(idx, record.getAmount())); } if (null != record.getCreateTime()) { int idx = cursor.add(); sql.append("create_time = ?,"); processors.add(p -> p.setTimestamp(idx, Timestamp.valueOf(record.getCreateTime()))); } if (null != record.getEditTime()) { int idx = cursor.add(); sql.append("edit_time = ?,"); processors.add(p -> p.setTimestamp(idx, Timestamp.valueOf(record.getEditTime()))); } StringBuilder realSql = new StringBuilder(sql.substring(0, sql.lastIndexOf(","))); int idx = cursor.add(); processors.add(p -> p.setLong(idx, record.getId())); realSql.append(" WHERE id = ?"); return jdbcTemplate.update(realSql.toString(), p -> { for (PreparedStatementProcessor processor : processors) { processor.process(p); } }); } @Override public Order selectOneByOrderId(String orderId) { return jdbcTemplate.query("SELECT * FROM t_order WHERE order_id = ?", p -> p.setString(1, orderId), SINGLE); } @Override public List<Order> selectByUserId(Long userId) { return jdbcTemplate.query("SELECT * FROM t_order WHERE order_id = ?", p -> p.setLong(1, userId), MULTI); } private static class Cursor { private int idx; public int add() { idx++; return idx; } public int idx() { return idx; } } }