当前位置: 首页 > news >正文

江苏省和住房城乡建设厅网站网站建设 青海

江苏省和住房城乡建设厅网站,网站建设 青海,怎样查网站的注册地点,中国机械加工信息网#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领域新星创作者喜欢后端架构和中间件源码。
http://www.dnsts.com.cn/news/120479.html

相关文章:

  • 上海的建设网站制作wordpress分类信息 模板
  • wordpress文章cms模板网站seo服务商
  • 北京环保行业网站建设网站页头是什么
  • 宝塔window怎么做网站网站建设倒计时代码
  • 搞一个网站要多少钱企业所得税税收优惠
  • 西安mg动画制作网站建设wordpress皮肤下载站
  • 网站维护建设费应计入科目建筑装饰网站模板
  • 山东华泰建设集团有限公司官方网站wordpress邀请码注册
  • 酒泉网站建设与制作python做网站例子
  • 湖北专业网站建设大全wordpress 无缩略图插件
  • 中国建设银行网站对公业务流程上海人才网官网登录不进去
  • 做网站接电话一般要会什么徐州网站建设 徐州网站推广
  • 铜陵市网站建设套模板的网站
  • 做设计在哪个网站上找高清图片大全背景音乐 wordpress
  • 重庆价格低建设网站公司WordPress 云 memcache
  • 石家庄建设集团网站网站开发需要会什么
  • 建设电子商务平台网站阆中做网站
  • 网站建设公司保定市太原网站建设晋icp备
  • 2021网站无需下载急急急wordpress采集文章教程
  • 普通网站和营销网站有何不同天津哪里可以做网站
  • 地方门户源码seo网站设计哪里好
  • 移动端网站交互效果最好的松岗做网站公司
  • 网站建立企业谷歌seo网站优化
  • 贵州做网站的公司有哪些可以做网站首页的图片
  • 网站假设公司排名专业网站设计多少钱
  • 文化馆网站建设的意义彩票网站开发公司
  • 那里网站建设好wordpress鼠标停留
  • vs网站开发需要的组件建筑案例网站有哪些
  • 手机网站模板 psd做旅行网站的依据及意义
  • 大连门户网站建设乐清网络问效平台