江苏省和住房城乡建设厅网站,网站建设 青海,怎样查网站的注册地点,中国机械加工信息网#x1f44f;作者简介#xff1a;大家好#xff0c;我是爱敲代码的小黄#xff0c;独角兽企业的Java开发工程师#xff0c;CSDN博客专家#xff0c;阿里云专家博主#x1f4d5;系列专栏#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙… 作者简介大家好我是爱敲代码的小黄独角兽企业的Java开发工程师CSDN博客专家阿里云专家博主系列专栏Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列如果感觉博主的文章还不错的话请三连支持一下博主哦博主正在努力完成2023计划中以梦为马扬帆起航2023追梦人联系方式hls1793929520加我进群大家一起学习一起进步 文章目录Spring 事务源码解析一、引言二、事务的本质1、JDBC的事务2、Spring的事务2.1 xml配置2.2 注解配置三、Spring事务源码剖析1、TransactionManager1.1 获取事务1.2 提交事务1.3 回滚事务2、 事务AOP的实现2.1 为什么使用AOP2.2 EnableTransactionManagement2.3 TransactionInterceptor2.4 XML配置四、流程图五、总结Spring 事务源码解析
一、引言
对于Java开发者而言关于 Spring 我们一般当做黑盒来进行使用不需要去打开这个黑盒。
但随着目前程序员行业的发展我们有必要打开这个黑盒去探索其中的奥妙。
本期 Spring 源码解析系列文章将带你领略 Spring 源码的奥秘
本期源码文章吸收了之前 Kafka 源码文章的错误将不再一行一行的带大家分析源码我们将一些不重要的部分当做黑盒处理以便我们更快、更有效的阅读源码。
废话不多说发车
本篇目录如下 本文流程图可关注公众号爱敲代码的小黄回复事务 获取 贴心的小黄为大家准备的文件格式为 POS文件方便大家直接导入 ProcessOn 修改使用 二、事务的本质 数据库事务(Database Transaction) 是指作为单个逻辑工作单元执行的一系列操作要么完全地执行要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元可以简化错误恢复并使应用程序更加可靠。 一个逻辑工作单元要成为事务必须满足所谓的 ACID原子性、一致性、隔离性和持久性属性。事务是数据库运行中的逻辑工作单位由DBMS中的事务管理子系统负责事务的处理。 1、JDBC的事务
我们来看一下在 JDBC 中对事务的操作处理
public class JDBCTransactionExample {public static void main(String[] args) {Connection conn null;PreparedStatement pstmt1 null;PreparedStatement pstmt2 null;try {// 加载驱动Class.forName(com.mysql.jdbc.Driver);// 获取连接conn DriverManager.getConnection(jdbc:mysql://localhost:3306/test, root, password);// 关闭自动提交开启事务conn.setAutoCommit(false);// 创建SQL语句String sql1 UPDATE account SET balance balance - ? WHERE id ?;String sql2 UPDATE account SET balance balance ? WHERE id ?;// 创建PreparedStatement对象pstmt1 conn.prepareStatement(sql1);pstmt2 conn.prepareStatement(sql2);// 设置参数pstmt1.setDouble(1, 1000);pstmt1.setInt(2, 1);pstmt2.setDouble(1, 1000);pstmt2.setInt(2, 2);// 执行更新操作int count1 pstmt1.executeUpdate();int count2 pstmt2.executeUpdate();if (count1 0 count2 0) {System.out.println(转账成功);// 提交事务conn.commit();} else {System.out.println(转账失败);// 回滚事务conn.rollback();}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {try {if (conn ! null) {// 回滚事务conn.rollback();}} catch (SQLException e1) {e1.printStackTrace();}e.printStackTrace();} finally {try {if (pstmt1 ! null) {pstmt1.close();}if (pstmt2 ! null) {pstmt2.close();}if (conn ! null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}
}
上面的代码我相信大部分的人都应该接触过这里也就不多说了
主要我们看几个重点步骤
获取连接Connection conn DriverManager.getConnection(jdbc:mysql://localhost:3306/test, root, password)关闭自动提交开启事务conn.setAutoCommit(false)提交事务conn.commit()回滚事务conn.rollback()
2、Spring的事务
我们在日常生产项目中项目由 Controller、Serivce、Dao 三层进行构建。 我们从上图中可以了解到
对于 addUser 方法实际对于数据调用来说分别调用了 insertUser()、insertLog 方法对数据库的操作为两次
我们要保证 addUser 方法是符合事务定义的。
2.1 xml配置
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:phttp://www.springframework.org/schema/pxmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd!-- 开启扫描 --context:component-scan base-packagecom.dpb.*/context:component-scan!-- 配置数据源 --bean classorg.springframework.jdbc.datasource.DriverManagerDataSource iddataSourceproperty nameurl valuejdbc:oracle:thin:localhost:1521:orcl/property namedriverClassName valueoracle.jdbc.driver.OracleDriver/property nameusername valuepms/property namepassword valuepms//bean!-- 配置JdbcTemplate --bean classorg.springframework.jdbc.core.JdbcTemplate constructor-arg namedataSource refdataSource//bean!-- Spring中使用XML配置事务三大步骤 1. 创建事务管理器 2. 配置事务方法 3. 配置AOP--bean classorg.springframework.jdbc.datasource.DataSourceTransactionManager idtransactionManagerproperty namedataSource refdataSource//beantx:advice idadvice transaction-managertransactionManagertx:attributestx:method namefun* propagationREQUIRED//tx:attributes/tx:advice!-- aop配置 --aop:configaop:pointcut expressionexecution(* *..service.*.*(..)) idtx/aop:advisor advice-refadvice pointcut-reftx//aop:config
/beans2.2 注解配置
首先必须要添加 EnableTransactionManagement 注解保证事务注解生效
EnableTransactionManagement
public class AnnotationMain {public static void main(String[] args) {}
}其次在方法上添加 Transactional 代表注解生效
Transactional
public int insertUser(User user) {userDao.insertUser();userDao.insertLog();return 1;
}上面的操作涉及两个重点 事务的传播属性 事务的隔离级别
三、Spring事务源码剖析
本次剖析源码我们会尽量挑重点来讲因为事务源码本身就是依靠 AOP 实现的我们之前已经很详细的讲过 IOC 和 AOP 的源码实现了这次带大家一起过一遍事务即可。
因为从博主本身而言我感觉 Spring 事务其实没有那么的重要面试也不常考所以不会花大量的时间去剖析细节源码。
1、TransactionManager
首先我们看一下这个接口的一些组成配置
****
这里我们重点看 PlatformTransactionManager 的实现其实现一共三个方法
获取事务TransactionStatus getTransaction(Nullable TransactionDefinition definition)提交事务void commit(TransactionStatus status)回滚事务void rollback(TransactionStatus status)
我们分别看一下其如何实现的
1.1 获取事务
我们想一下在获取事务这一阶段我们会做什么功能呢
参考上述我们 JDBC 的步骤这个阶段应该会 创建连接并且开启事务
public final TransactionStatus getTransaction(Nullable TransactionDefinition definition){// PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEWPROPAGATION_NESTED都需要新建事务if (def.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRED ||def.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRES_NEW ||def.getPropagationBehavior() TransactionDefinition.PROPAGATION_NESTED) {//没有当前事务的话REQUIREDREQUIRES_NEWNESTED挂起的是空事务然后创建一个新事务SuspendedResourcesHolder suspendedResources suspend(null);try {// 看这里重点开始事务return startTransaction(def, transaction, debugEnabled, suspendedResources);}catch (RuntimeException | Error ex) {// 恢复挂起的事务resume(null, suspendedResources);throw ex;}}
}private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, Nullable SuspendedResourcesHolder suspendedResources) {// 是否需要新同步boolean newSynchronization (getTransactionSynchronization() ! SYNCHRONIZATION_NEVER);// 创建新的事务DefaultTransactionStatus status newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 【重点】开启事务和连接doBegin(transaction, definition);// 新同步事务的设置针对于当前线程的设置prepareSynchronization(status, definition);return status;
}protected void doBegin(Object transaction, TransactionDefinition definition) {// 判断事务对象没有数据库连接持有器if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {// 【重点】通过数据源获取一个数据库连接对象Connection newCon obtainDataSource().getConnection();// 把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去// 再次进来时该 txObject 就已经有事务配置了txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}// 【重点】获取连接con txObject.getConnectionHolder().getConnection();// 为当前的事务设置隔离级别【数据库的隔离级别】Integer previousIsolationLevel DataSourceUtils.prepareConnectionForTransaction(con, definition);// 设置先前隔离级别txObject.setPreviousIsolationLevel(previousIsolationLevel);// 设置是否只读txObject.setReadOnly(definition.isReadOnly());// 关闭自动提交if (con.getAutoCommit()) {//设置需要恢复自动提交txObject.setMustRestoreAutoCommit(true);// 【重点】关闭自动提交con.setAutoCommit(false);}// 判断事务是否需要设置为只读事务prepareTransactionalConnection(con, definition);// 标记激活事务txObject.getConnectionHolder().setTransactionActive(true);// 设置事务超时时间int timeout determineTimeout(definition);if (timeout ! TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 绑定我们的数据源和连接到我们的同步管理器上把数据源作为key,数据库连接作为value 设置到线程变量中if (txObject.isNewConnectionHolder()) {// 将当前获取到的连接绑定到当前线程TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}}
}到这里我们的 获取事务 接口完成了 数据库连接的创建 和 关闭自动提交开启事务将 Connection 注册到了缓存resources当中便于获取。
1.2 提交事务
public final void commit(TransactionStatus status) throws TransactionException {DefaultTransactionStatus defStatus (DefaultTransactionStatus) status;// 如果在事务链中已经被标记回滚那么不会尝试提交事务直接回滚if (defStatus.isLocalRollbackOnly()) {// 不可预期的回滚processRollback(defStatus, false);return;}// 设置了全局回滚if (!shouldCommitOnGlobalRollbackOnly() defStatus.isGlobalRollbackOnly()) {// 可预期的回滚可能会报异常processRollback(defStatus, true);return;}// 【重点】处理事务提交processCommit(defStatus);
}// 处理提交先处理保存点然后处理新事务如果不是新事务不会真正提交要等外层是新事务的才提交
// 最后根据条件执行数据清除,线程的私有资源解绑重置连接自动提交隔离级别是否只读释放连接恢复挂起事务等
private void processCommit(DefaultTransactionStatus status) throws TransactionException {;// 如果是独立的事务则直接提交doCommit(status);//根据条件完成后数据清除,和线程的私有资源解绑重置连接自动提交隔离级别是否只读释放连接恢复挂起事务等cleanupAfterCompletion(status);
}这里比较重要的有两个步骤 doCommit提交事务直接使用 JDBC 提交即可 protected void doCommit(DefaultTransactionStatus status) {DataSourceTransactionObject txObject (DataSourceTransactionObject) status.getTransaction();Connection con txObject.getConnectionHolder().getConnection();try {// JDBC连接提交con.commit();}catch (SQLException ex) {throw new TransactionSystemException(Could not commit JDBC transaction, ex);}
}cleanupAfterCompletion数据清除与线程中的私有资源解绑方便释放 // 线程同步状态清除
TransactionSynchronizationManager.clear();// 清除同步状态【这些都是线程的缓存使用ThreadLocal的】
public static void clear() {synchronizations.remove();currentTransactionName.remove();currentTransactionReadOnly.remove();currentTransactionIsolationLevel.remove();actualTransactionActive.remove();
}
// 如果是新事务的话进行数据清除线程的私有资源解绑重置连接自动提交隔离级别是否只读释放连接等
doCleanupAfterCompletion(status.getTransaction());// 此方法做清除连接相关操作比如重置自动提交啊只读属性啊解绑数据源啊释放连接啊清除链接持有器属性
protected void doCleanupAfterCompletion(Object transaction) {DataSourceTransactionObject txObject (DataSourceTransactionObject) transaction;// 将数据库连接从当前线程中解除绑定TransactionSynchronizationManager.unbindResource(obtainDataSource());// 释放连接Connection con txObject.getConnectionHolder().getConnection();// 恢复数据库连接的自动提交属性con.setAutoCommit(true);// 重置数据库连接DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());// 如果当前事务是独立的新创建的事务则在事务完成时释放数据库连接DataSourceUtils.releaseConnection(con, this.dataSource);// 连接持有器属性清除txObject.getConnectionHolder().clear();}这就是我们提交事务的操作了总之来说主要就是 调用JDBC的commit提交 和 清除一系列的线程内部数据和配置
1.3 回滚事务
public final void rollback(TransactionStatus status) throws TransactionException {DefaultTransactionStatus defStatus (DefaultTransactionStatus) status;processRollback(defStatus, false);
}private void processRollback(DefaultTransactionStatus status, boolean unexpected) {// 回滚的擦欧洲哦doRollback(status);// 回滚完成后回调triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);// 根据事务状态信息完成后数据清除和线程的私有资源解绑重置连接自动提交隔离级别是否只读释放连接恢复挂起事务等cleanupAfterCompletion(status);
}protected void doRollback(DefaultTransactionStatus status) {DataSourceTransactionObject txObject (DataSourceTransactionObject) status.getTransaction();Connection con txObject.getConnectionHolder().getConnection();// jdbc的回滚con.rollback();
}回滚事务简单来说 调用JDBC的rollback 和 清除数据
2、 事务AOP的实现
我们来思考一下利用 TransactionManager 重写一下我们第一步的 JDBC 的功能
Autowiredprivate UserDao userDao;Autowiredprivate PlatformTransactionManager txManager;Autowiredprivate LogService logService;Transactionalpublic void insertUser(User u) {// 1、创建事务定义DefaultTransactionDefinition definition new DefaultTransactionDefinition();// 2、根据定义开启事务TransactionStatus status txManager.getTransaction(definition);try {this.userDao.insert(u);Log log new Log(System.currentTimeMillis() , System.currentTimeMillis() - u.getUserName());// this.doAddUser(u);this.logService.insertLog(log);// 3、提交事务txManager.commit(status);} catch (Exception e) {// 4、异常了回滚事务txManager.rollback(status);throw e;}}大家看到上述代码及思考一下 AOP 的作用和源码有没有一丝丝想法
比如我现在是面试官问你一个问题你怎么去设计 Spring 的事务
如果一点点想法都没有的话也不用着急我们来慢慢的分析
2.1 为什么使用AOP
我们想如果我们要实现事务在每一个方法里面都需要进行以下三个步骤
获取事务提交事务回滚事务
是不是显得我们的代码很臃肿那么我们能不能把这三个步骤搞成一个通用化的东西
一些代码在方法前执行一些代码方法后执行
这个时候你是不是就想到了 AOP切面编程了
当然Spring 中也是如此做的利用 AOP 来对事务进行了统一的包装实现
2.2 EnableTransactionManagement
我们知道了使用 AOP 技术实现那到底是如何实现的呢
我们从 EnableTransactionManagement 注解聊起我们点进该注解
Import(TransactionManagementConfigurationSelector.class)
public interface EnableTransactionManagement {很明显TransactionManagementConfigurationSelector 类是我们主要关注的内容
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelectorEnableTransactionManagement {/*** 此处是AdviceMode的作用默认是用代理另外一个是ASPECTJ*/Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {determineTransactionAspectClass()};default:return null;}}
}一共注册了两个 AutoProxyRegistrar.class注册AOP处理器 ProxyTransactionManagementConfiguration.class代理事务配置注册事务需要用的一些类而且RoleROLE_INFRASTRUCTURE都是属于内部级别的 Configuration(proxyBeanMethods false)
Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {Bean(name TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {// 【重点】注册了 BeanFactoryTransactionAttributeSourceAdvisor 的 advisor// 其 advice 为 transactionInterceptorBeanFactoryTransactionAttributeSourceAdvisor advisor new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource);advisor.setAdvice(transactionInterceptor);if (this.enableTx ! null) {advisor.setOrder(this.enableTx.IntegergetNumber(order));}return advisor;}BeanRole(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}BeanRole(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {TransactionInterceptor interceptor new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource);if (this.txManager ! null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}}到这里看到 BeanFactoryTransactionAttributeSourceAdvisor 以 advisor 结尾的类AOP 的 DNA 应该动了其 advice 为 transactionInterceptor 到这里我们思考一下利用我们之前学习到的 AOP 的源码猜测其运行逻辑 我们在方法上写上 EnableTransactionManagement 注解Spring 会注册一个 BeanFactoryTransactionAttributeSourceAdvisor 的类创建对应的方法 Bean 时会和 AOP 一样利用该 Advisor 类生成对应的代理对象最终调用方法时会调用代理对象并通过环绕增强来达到事务的功能
2.3 TransactionInterceptor
我们从上面看到其 advice 正是 TransactionInterceptor那自然不用多说
从上篇 AOP 得知代理对象运行时会拿到所有的 advice 并进行排序责任链递归运行
所以我们直接看 TransactionInterceptor 这个类即可
这里先看一下 TransactionInterceptor 类图
然后看其源码内容
这里的 invoke 方法怎么执行到的我就不多介绍了看过上篇 AOP 的文章应该都懂不熟悉的小伙伴可以去看一下
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {OverrideNullablepublic Object invoke(MethodInvocation invocation) throws Throwable {// 获取我们的代理对象的class属性Class? targetClass (invocation.getThis() ! null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupports invokeWithinTransaction.../*** 以事务的方式调用目标方法* 在这埋了一个钩子函数 用来回调目标方法的*/return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}
}Nullable
protected Object invokeWithinTransaction(Method method, Nullable Class? targetClass, final InvocationCallback invocation){// 获取我们的事务属性源对象TransactionAttributeSource tas getTransactionAttributeSource();// 通过事务属性源对象获取到当前方法的事务属性信息final TransactionAttribute txAttr (tas ! null ? tas.getTransactionAttribute(method, targetClass) : null);// 获取我们配置的事务管理器对象final TransactionManager tm determineTransactionManager(txAttr);if (txAttr null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// 【重点】创建TransactionInfoTransactionInfo txInfo createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);try {// 执行被增强方法,调用具体的处理逻辑【我们实际的方法】retVal invocation.proceedWithInvocation();}catch (Throwable ex) {// 异常回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//清除事务信息恢复线程私有的老的事务信息cleanupTransactionInfo(txInfo);}//成功后提交会进行资源储量连接释放恢复挂起事务等操作commitTransactionAfterReturning(txInfo);return retVal;}
}// 创建连接 开启事务
protected TransactionInfo createTransactionIfNecessary(Nullable PlatformTransactionManager tm,Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// 获取TransactionStatus事务状态信息status tm.getTransaction(txAttr);// 根据指定的属性与status准备一个TransactionInforeturn prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}// 存在异常时回滚事务
protected void completeTransactionAfterThrowing(Nullable TransactionInfo txInfo, Throwable ex) {// 进行回滚txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}// 调用事务管理器的提交方法
protected void commitTransactionAfterReturning(Nullable TransactionInfo txInfo){txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}然后…没有然后了
事务就是这样简单、朴实无华的实现了
2.4 XML配置
这里稍微讲下 xml 配置的xml 也一样在我们进行 xml 文件解析的时候将 BeanFactoryTransactionAttributeSourceAdvisor 组装起来注册到 BeanDefinitionMap 中
这里可以参考上篇 AOP 的解析和生成
生成后也一样调用的是代理方法判断改方法有没有被代理然后递归责任链执行 Advice 即可
没什么困难的
四、流程图
大家有没有感觉事务有点水就是用了 Spring AOP 的功能包装了一下
根本的实现还是依靠的 JDBC但有一些不得不记的小知识点事务的传播属性 和 事务的隔离级别
这两个关于配置的还是要去看一下我们本篇就不再多叙述了网上好多资料都有的
我们画一下基本的流程图 整个流程也相较于简单有兴趣的可以去更细的看一下
五、总结
记得校招时候当时对 Spring 懵懂无知转眼间也被迫看了源码
本文主要从 JDBC 组装事务过度到 Spring 的事务注解最终通过 AOP 的技术去进行切面处理
通过这篇文章我相信99% 的人应该都可以理解了 Spring 事务 的来龙去脉
那么如何证明你真的理解了 Spring 事务呢我这里出个经典的题目大家可以想一下如果让你设计Spring中事务的流程你会如何设计
如果你能看到这那博主必须要给你一个大大的鼓励谢谢你的支持
喜欢的可以点个关注后续会更新 Spring 循环依赖 的源码文章
我是爱敲代码的小黄独角兽企业的Java开发工程师CSDN博客专家Java领域新星创作者喜欢后端架构和中间件源码。