关于springboot商城系统教程及源码的信息

7283商城 107 0

【导读】深圳智能佳利科技整理:springboot商城系统教程及源码??的问答,免费开源电商系统就YSHOP柒贰捌叁商城,“”的正文阅读:

全文目录一览:

[Spring boot源码解析] 2 启动流程分析

springboot商城系统教程及源码了解 Spring Boot springboot商城系统教程及源码的启动流程的时候,springboot商城系统教程及源码我们先看一下一个Spring Boot 应用是如何启动的,如下是一个简单的 SpringBoot 程序,非常的简洁,他是如何做到的呢,我们接下来就将一步步分解。

我们追踪 SpringApplication.run() 方法,其实最终它主要的逻辑是新建一个 SpringApplication ,然后调用他的 run 方法,如下:

我们先来看一下创建 SpringApplication 的方法:

在将Main class 设置 primarySources 后,调用springboot商城系统教程及源码了 WebApplicationType.deduceFromClasspath() 方法,该方法是为了检查当前的应用类型,并设置给 webApplicationType 。 我们进入 deduceFromClasspath 方法 :

这里主要是通过类加载器判断是否存在 REACTIVE 相关的类信息,假如有就代表是一个 REACTIVE 的应用,假如不是就检查是否存在 Servelt 和 ConfigurableWebApplicationContext ,假如都没有,就代表应用为非 WEB 类应用,返回 NONE ,默认返回 SERVLET 类型,我们这期以我们目前最常使用的 SERVLET 类型进行讲解,所以我们在应用中引入了 spring-boot-starter-web 作为依赖:

他会包含 Spring-mvc 的依赖,所以就包含了内嵌 tomcat 中的 Servlet 和 Spring-web 中的 ConfigurableWebApplicationContext ,因此返回了 SERVLET 类型。

回到刚才创建 SpringApplication 的构建方法中,我们设置完成应用类型后,就寻找所有的 Initializer 实现类,并设置到 SpringApplication 的 Initializers 中,这里先说一下 getSpringFactoriesInstances 方法,我们知道在我们使用 SpringBoot 程序中,会经常在 META-INF/spring.factories 目录下看到一些 EnableAutoConfiguration ,来出发 config 类注入到容器中,我们知道一般一个 config 类要想被 SpringBoot 扫描到需要使用 @CompnentScan 来扫描具体的路径,对于 jar 包来说这无疑是非常不方便的,所以 SpringBoot 提供了另外一种方式来实现,就是使用 spring.factories ,比如下面这个,我们从 Springboot-test 中找到的例子,这里先定义了一个ExampleAutoConfiguration,并加上了 Configuration 注解:

然后在 spring.factories 中定义如下:

那这种方式是怎么实现的你,这就要回到我们刚才的方法 getSpringFactoriesInstances :

我们先来看一下传入参数,这里需要注意的是 args,这个是初始化对应 type 的时候传入的构造参数,我们先看一下 SpringFactoriesLoader#loadFactoryNames 方法:

首先是会先检查缓存,假如缓存中存在就直接返回,假如没有就调用 classLoader#getResources 方法,传入 META-INF/spring.factories ,即获取所有 jar 包下的对应文件,并封装成 UrlResource ,然后使用 PropertiesLoaderUtils 将这些信息读取成一个对一对的 properties,我们观察一下 spring.factories 都是按 properties 格式排版的,假如有多个就用逗号隔开,所以这里还需要将逗号的多个类分隔开来,并加到 result 中,由于 result 是一个 LinkedMultiValueMap 类型,支持多个值插入,最后放回缓存中。最终完成加载 META-INF/spring.factories 中的配置,如下:

我们可以看一下我们找到的 initializer 有多少个:

在获取到所有的 Initializer 后接下来是调用 createSpringFactoriesInstances 方法进行初始化。

这里的 names 就是我们上面通过类加载器加载到的类名,到这里会先通过反射生成 class 对象,然后判断该类是否继承与 ApplicationContextInitializer ,最后通过发射的方式获取这个类的构造方法,并调用该构造方法,传入已经定义好的构造参数,对于 ApplicationContextInitializer 是无参的构造方法,然后初始化实例并返回,回到原来的方法,这里会先对所有的 ApplicationContextInitializer 进行排序,调用 AnnotationAwareOrderComparator#sort(instances) 方法,这里就是根据 @Order 中的顺序进行排序。

接下来是设置 ApplicationListener ,我们跟进去就会发现这里和上面获取 ApplicationContextInitializer 的方法如出一辙,最终会加载到如图的 15 个 listener (这里除了 EnableEncryptablePropertiesBeanFactoryPostProcessor 外,其他都是 SpringBoot 内部的 Listener):

在完成 SpringApplication 对象的初始化后,我们进入了他的 run 方法,这个方法几乎涵盖了 SpringBoot 生命周期的所有内容,主要分为九个步骤,每一个步骤这里都使用注解进行标识:

主要步骤如下:

第一步:获取 SpringApplicationRunListener, 然后调用他的 staring 方法启动监听器。

第二步:根据 SpringApplicationRunListeners以及参数来准备环境。

第三步:创建 Spring 容器。

第四步:Spring 容器的前置处理。

第五步:刷新 Spring 容器。

第六步: Spring 容器的后置处理器。

第七步:通知所有 listener 结束启动。

第八步:调用所有 runner 的 run 方法。

第九步:通知所有 listener running 事件。

我们接下来一一讲解这些内容。

我们首先看一下第一步,获取 SpringApplicationRunListener :

这里和上面获取 initializer 和 listener 的方式基本一致,都是通过 getSpringFactoriesInstances , 最终只找到一个类就是: org.springframework.boot.context.event.EventPublishingRunListener ,然后调用其构造方法并传入产生 args , 和 SpringApplication 本身:

我们先看一下构造函数,首先将我们获取到的 ApplicationListener 集合添加到initialMulticaster 中, 最后都是通过操作 SimpleApplicationEventMulticaster 来进行广播,我,他继承于 AbstractApplicationEventMulticaster ,我们先看一下他的 addApplicationListener 方法:

我们可以看出,最后是放到了 applicationListenters 这个容器中。他是 defaultRetriever 的成员属性, defaultRetriever 则是 AbstractApplicationEventMulticaster 的私有类,我们简单看一下这个类:

我们只需要看一下这里的 getApplicationListeners 方法,它主要是到 beanFactory 中检查是否存在多的 ApplicationListener 和旧的 applicationListeners 组合并返回,接着执行 listener 的 start 方法,最后也是调用了 AbstractApplicationEventMulticaster 的 multicastEvent 查找支持对应的 ApplicationEvent 类型的通知的 ApplicationListener 的 onApplicationEvent 方法 ,这里除了会:

筛选的方法如下,都是调用了对应类型的 supportsEventType 方法 :

如图,我们可以看到对 org.springframework.boot.context.event.ApplicationStartingEvent 感兴趣的有5个 Listener

环境准备的具体方法如下:

首先是调用 getOrCreateEnvironment 方法来创建 environment ,我们跟进去可以发现这里是根据我们上面设置的环境的类型来进行选择的,当前环境会创建 StandardServletEnvironment

我们先来看一下 StandardServletEnvironment 的类继承关系图,我们可以看出他是继承了 AbstractEnvironment :

他会调用子类的 customizePropertySources 方法实现,首先是 StandardServletEnvironment 的实现如下,他会添加 servletConfigInitParams , servletContextInitParams , jndiProperties 三种 properties,当前调试环境没有配置 jndi properties,所以这里不会添加。接着调用父类的 customizePropertySources 方法,即调用到了 StandardEnvironment 。

我们看一下 StandardEnvironment#customizePropertySources 方法,与上面的三个 properties 创建不同,这两个是会进行赋值的,包括系统环境变量放入 systemEnvironment 中,jvm 先关参数放到 systemProperties 中:

这里会添加 systemEnvironment 和 systemProperties 这两个 properties,最终拿到的 properties 数量如下 4个:

在创建完成 Environment 后,接下来就到了调用 configureEnvironment 方法:

我们先看一下 configurePropertySources 方法,这里主要分两部分,首先是查询当前是否存在 defaultProperties ,假如不为空就会添加到 environment 的 propertySources 中,接着是处理命令行参数,将命令行参数作为一个 CompositePropertySource 或则 SimpleCommandLinePropertySource 添加到 environment 的 propertySources 里面,

接着调用 ConfigurationPropertySources#attach 方法,他会先去 environment 中查找 configurationProperties , 假如寻找到了,先检查 configurationProperties 和当前 environment 是否匹配,假如不相等,就先去除,最后添加 configurationProperties 并将其 sources 属性设置进去。

回到我们的 prepareEnvironment 逻辑,下一步是通知观察者,发送 ApplicationEnvironmentPreparedEvent 事件,调用的是 SpringApplicationRunListeners#environmentPrepared 方法,最终回到了 SimpleApplicationEventMulticaster#multicastEvent 方法,我们通过 debug 找到最后对这个时间感兴趣的 Listener 如下:

其主要逻辑如下:

这个方法最后加载了 PropertySourceLoader , 这里主要是两种,一个是用于 Properties 的,一个是用于 YAML 的如下:

其中 apply 方法主要是加载 defaultProperties ,假如已经存在,就进行替换,而替换的目标 PropertySource 就是 load 这里最后的一个 consumer 函数加载出来的,这里列一下主要做的事情:

1、加载系统中设置的所有的 Profile 。

2、遍历所有的 Profile ,假如是默认的 Profile , 就将这个 Profile 加到 environment 中。

3、调用load 方法,加载配置,我们深入看一下这个方法:

他会先调用 getSearchLocations 方法,加载所有的需要加载的路径,最终有如下路径:

其核心方法是遍历所有的 propertySourceLoader ,也就是上面加载到两种 propertySourceLoader ,最红 loadForFileExtension 方法,加载配置文件,这里就不展开分析了,说一下主要的作用,因为每个 propertySourceLoader 都有自己可以加载的扩展名,默认扩展名有如下四个 properties, xml, yml, yaml,所以最终拿到文件名字,然后通过 - 拼接所有的真实的名字,然后加上路径一起加载。

接下来,我们分析 BackgroundPreinitializer ,这个方法在接收 ApplicationPrepareEnvironment 事件的时候真正调用了这份方法:

1、 ConversionServiceInitializer 主要负责将包括 日期,货币等一些默认的转换器注册到 formatterRegistry 中。

2、 ValidationInitializer 创建 validation 的匹配器。

3、 MessageConverterInitializer 主要是添加了一些 http 的 Message Converter。

4、 JacksonInitializer 主要用于生成 xml 转换器的。

接着回到我们将的主体方法, prepareEnvironment 在调用完成 listeners.environmentPrepared(environment) 方法后,调用 bindToSpringApplication(environment) 方法,将 environment 绑定到 SpirngApplication 中。

接着将 enviroment 转化为 StandardEnvironment 对象。

最后将 configurationProperties 加入到 enviroment 中, configurationProperties 其实是将 environment 中其他的 PropertySource 重新包装了一遍,并放到 environment 中,这里主要的作用是方便 PropertySourcesPropertyResolver 进行解析。

它主要是检查是否存在 spring.beaninfo.ignore 配置,这个配置的主要作用是设置 javaBean 的内省模式,所谓内省就是应用程序在 Runtime 的时候能检查对象类型的能力,通常也可以称作运行时类型检查,区别于反射主要用于修改类属性,内省主要用户获取类属性。那么我们什么时候会使用到内省呢,java主要是通过内省工具 Introspector 来完成内省的工作,内省的结果通过一个 Beaninfo 对象返回,主要包括类的一些相关信息,而在 Spring中,主要是 BeanUtils#copyProperties 会使用到,Spring 对内省机制还进行了改进,有三种内省模式,如下图中红色框框的内容,默认情况下是使用 USE_ALL_BEANINFO。假如设置为true,就是改成第三中 IGNORE_ALL_BEANINFO

首先是检查 Application的类型,然后获取对应的 ApplicationContext 类,我们这里是获取到了 org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext 接着调用 BeanUtils.instantiateClass(contextClass); 方法进行对象的初始化。

最终其实是调用了 AnnotationConfigServletWebServerApplicationContext 的默认构造方法。我们看一下这个方法做了什么事情。这里只是简单的设置了一个 reader 和一个 scanner,作用于 bean 的扫描工作。

我们再来看一下这个类的继承关系

这里获取 ExceptionReporter 的方式主要还是和之前 Listener 的方式一致,通过 getSpringFactoriesInstances 来获取所有的 SpringBootExceptionReporter 。

其主要方法执行如下:

springboot启动源码

一、找到启动类

1.java -jar xxx.jar

java会找到MANIFEST.MF文件springboot商城系统教程及源码的Main-Class,启动springboot JarLauncher的main方法

2.JarLauncher.launch方法大致过程

1)获取到BOOT-INF下面的classes文件与lib包下面的jar

2)创建LaunchedURLClassLoader,放入线程上下文,用于加载jar(可以加载jar中jar)

3.获取到Start-Class启动类,利用反射,调用main方法,这样就能到达springboot商城系统教程及源码我们使用的main方法了。

二、Main方法启动

1.初始化SpringApplication

1). 获取启动类

2).获取web应用类型

3).读取了对外扩展的ApplicationContextInitializer ,ApplicationListener

4).根据main推算出所在的类

2.启动

2.1)启动事件

2.2 步骤

1).启动事件,通知我要启动了

listeners.starting();

2).获取环境运行的参数,通过environmentPrepared会初始化properties和yml文件。

3).根据容器类型获取applicationcontext,SERVLET获取AnnotationConfigServletWebServerApplicationContext

4).填充applicationcontext,并发布上下文已准备事件(contextPrepared),加载主类配置,发布contextLoaded事件

5).执行applicationcontext.refresh方法,并启动内置tomcat。

6).发布started和running事件

SpringBoot内置生命周期事件详解 SpringBoot源码(十)

SpringBoot中文注释项目Github地址:

本篇接 SpringBoot事件监听机制源码分析(上) SpringBoot源码(九)

温故而知新,我们来简单回顾一下上篇springboot商城系统教程及源码的内容,上一篇我们分析springboot商城系统教程及源码了 SpringBoot启动时广播生命周期事件springboot商城系统教程及源码的原理 ,现将关键步骤再浓缩总结下:

上篇文章的侧重点是分析了SpringBoot启动时广播生命周期事件的原理,此篇文章我们再来详细分析SpringBoot内置的7种生命周期事件的源码。

分析SpringBoot的生命周期事件,我们先来看一张类结构图:

由上图可以看到事件类之间的关系:

EventObject 类是JDK的事件基类,可以说是所有Java事件类的基本,即所有的Java事件类都直接或间接继承于该类,源码如下:

可以看到 EventObject 类只有一个属性 source ,这个属性是用来记录最初事件是发生在哪个类,举个栗子,比如在SpringBoot启动过程中会发射 ApplicationStartingEvent 事件,而这个事件最初是在 SpringApplication 类中发射的,因此 source 就是 SpringApplication 对象。

ApplicationEvent 继承了DK的事件基类 EventObject 类,是Spring的事件基类,被所有Spring的具体事件类继承,源码如下:

可以看到 ApplicationEvent 有且仅有一个属性 timestamp ,该属性是用来记录事件发生的时间。

SpringApplicationEvent 类继承了Spring的事件基类 ApplicationEvent ,是所有SpringBoot内置生命周期事件的父类,源码如下:

可以看到 SpringApplicationEvent 有且仅有一个属性 args ,该属性就是SpringBoot启动时的命令行参数即标注 @SpringBootApplication 启动类中 main 函数的参数。

接下来我们再来看一下 SpringBoot 内置生命周期事件即 SpringApplicationEvent 的具体子类们。

SpringBoot开始启动时便会发布 ApplicationStartingEvent 事件,其发布时机在环境变量Environment或容器ApplicationContext创建前但在注册 ApplicationListener 具体监听器之后,标志标志 SpringApplication 开始启动。

可以看到 ApplicationEnvironmentPreparedEvent 事件多了一个 environment 属性,我们不妨想一下,多了 environment 属性的作用是啥springboot商城系统教程及源码

答案就是 ApplicationEnvironmentPreparedEvent 事件的 environment 属性作用是利用事件发布订阅机制,相应监听器们可以从 ApplicationEnvironmentPreparedEvent 事件中取出 environment 变量,然后我们可以为 environment 属性增加属性值或读出 environment 变量中的值。

当SpringApplication已经开始启动且环境变量 Environment 已经创建后,并且为环境变量 Environment 配置了命令行和 Servlet 等类型的环境变量后,此时会发布 ApplicationEnvironmentPreparedEvent 事件。

监听 ApplicationEnvironmentPreparedEvent 事件的第一个监听器是 ConfigFileApplicationListener ,因为是 ConfigFileApplicationListener 监听器还要为环境变量 Environment 增加 application.properties 配置文件中的环境变量;此后还有一些也是监听 ApplicationEnvironmentPreparedEvent 事件的其他监听器监听到此事件时,此时可以说环境变量 Environment 几乎已经完全准备好了。

可以看到 ApplicationContextInitializedEvent 事件多了个 ConfigurableApplicationContext 类型的 context 属性, context 属性的作用同样是为了相应监听器可以拿到这个 context 属性执行一些逻辑,具体作用将在 3.4.4 详述。

ApplicationContextInitializedEvent 事件在 ApplicationContext 容器创建后,且为 ApplicationContext 容器设置了 environment 变量和执行了 ApplicationContextInitializers 的初始化方法后但在bean定义加载前触发,标志ApplicationContext已经初始化完毕。

同样可以看到 ApplicationPreparedEvent 事件多了个 ConfigurableApplicationContext 类型的 context 属性,多了 context 属性的作用是能让监听该事件的监听器们能拿到 context 属性,监听器拿到 context 属性一般有如下作用:

ApplicationPreparedEvent 事件在 ApplicationContext 容器已经完全准备好时但在容器刷新前触发,在这个阶段 bean 定义已经加载完毕还有 environment 已经准备好可以用了。

ApplicationStartedEvent 事件将在容器刷新后但 ApplicationRunner 和 CommandLineRunner 的 run 方法执行前触发,标志 Spring 容器已经刷新,此时容器已经准备完毕了。

ApplicationReadyEvent 事件在调用完 ApplicationRunner 和 CommandLineRunner 的 run 方法后触发,此时标志 SpringApplication 已经正在运行。

可以看到 ApplicationFailedEvent 事件除了多了一个 context 属性外,还多了一个 Throwable 类型的 exception 属性用来记录SpringBoot启动失败时的异常。

ApplicationFailedEvent 事件在SpringBoot启动失败时触发,标志SpringBoot启动失败。

此篇文章相对简单,对SpringBoot内置的7种生命周期事件进行了详细分析。我们还是引用上篇文章的一张图来回顾一下这些生命周期事件及其用途:

由于有一些小伙伴们建议之前有些源码分析文章太长,导致耐心不够,看不下去,因此,之后的源码分析文章如果太长的话,笔者将会考虑拆分为几篇文章,这样就比较短小了,比较容易看完,嘿嘿。

【源码笔记】Github地址:

点赞搞起来,嘿嘿嘿!

公众号【 源码笔记 】专注于Java后端系列框架的源码分析。

15《Spring Boot 入门教程》多数据源与分布式事务

一个项目中使用多个数据源的需求,我们在日常工作中时常会遇到。

以商城系统为例,有一个 MySQL 的数据库负责存储交易数据。公司还有一套 ERP 企业信息化管理系统,要求订单信息同步录入 ERP 数据库,便于公司统一管理,而该 ERP 系统采用的数据库为 SQL Server 。

此时,就可以在 Spring Boot 项目中配置多个数据源。另外,使用多数据源后,需要采用分布式事务来保持数据的完整性。

本小节我们使用 Spring Boot 开发一个商城系统的订单生成功能,订单信息同时进入 MySQL 与 SQL Server 数据库。

首先创建 MySQL 数据库 shop ,并新建订单表 order ,表结构如下:

order 表结构

然后创建 SQL Server 数据库 erpshop ,并新建订单表 erp_order ,表结构如下。注意 id 是自增长的唯一标识,out_id 是对应订单在 MySQL 数据库中的唯一标识,以便在两个库中比对订单。

erp_order 结构

接下来,我们开始实现 Spring Boot 后端项目,数据持久层采用 MyBatis 框架,同时访问两个数据源。

Spring Boot 版本选择 2.2.5 ,Group 为 com.imooc , Artifact 为 spring-boot-multidb,生成项目后导入 Eclipse 开发环境。

我们引入热部署依赖、 Web 依赖、数据库访问相关依赖及测试相关依赖,具体如下:

实例:

由于我们要同时访问两个数据库,所以需要在配置文件中添加两个数据源的配置信息。注意配置多数据源时, url 配置需要使用 spring.datasource.db1.jdbc-url=xxx 的形式。

实例:

多个数据源的情况下, 我们需要通过配置类,将数据源注册为组件放入 Spring 容器中。

实例:

通过这个配置类, Spring 容器中就有两个数据源组件,这两个组件分别采用 spring.datasource.db1 和 spring.datasource.db2 开头的配置信息。所以通过这两个组件,就能分别操作 MySQL 数据源 1 和 SQL Sever 数据源 2 。

多数据源情况下, MyBatis 中的关键组件 SqlSessionFactory 和 SqlSessionTemplate 也需要单独配置,我们需要为两个数据源分别配置一套组件。

实例:

通过上面的配置类, com.imooc.springbootmultidb.mapper1 包中的 DAO 数据访问接口会自动调用 sqlSessionTemplate1 组件实现具体数据库操作,而 sqlSessionTemplate1 操作的数据源已经通过配置类设置为 db1 。同时, DAO 数据访问接口对应的映射文件已经指定到 classpath:mapper1/ 目录去寻找。这样数据源 – DAO 数据访问接口 – 映射文件三者的对应关系就建立起来了。

数据源 2 的配置方法是一样的, com.imooc.springbootmultidb.mapper2 包中的 DAO 数据访问接口会自动调用 sqlSessionTemplate2 组件,其操作的数据源即为 db2 ,其对应的映射文件指定到 classpath:mapper2/ 目录去寻找。

实例:

数据访问接口的位置已经在配置类指定,首先在 com.imooc.springbootmultidb.mapper1 创建 OrderDao ,操作的是数据源 1 中的 order 表。

实例:

然后在 com.imooc.springbootmultidb.mapper2 创建 ErpOrderDao ,操作的是数据源 2 中的 erporder 表。

实例:

这两个接口中使用的数据对象比较简单,代码如下:

实例:

分别针对 OrderDao 、 ErpOrderDao 编写对应的映射文件,然后按照配置类指定的位置,两个文件分别放到 resources/mapper1 和 resources/mapper2 目录下。

实例:

实例:

数据操作接口与对应的映射文件均已编写完毕,现在可以通过测试类进行多数据源测试了,我们在测试类中同时向两个库插入记录。

实例:

运行测试方法后,两个数据库表中均新增数据成功,这样我们就成功的使用 Spring Boot 同时操作了两个数据源。

采用多数据源之后,事务的实现方式也随之发生变化。当某个数据源操作出现异常时,该数据源和其他数据源的事务都需要回滚。这种涉及多个数据源的事务,称为分布式事务,接来下我们就来具体实现一下。

在 pom.xml 引入 Atomikos 事务管理器相关的依赖项, Atomikos 是一个开源的事务管理器,支持分布式事务。

实例:

需要将默认的数据源更换为支持分布式事务的数据源, MySQL 对应的数据源为 MysqlXADataSource , SQL Server 对应的数据源为 SQLServerXADataSource 。

实例:

继续修改 DataSourceConfig 类,在其中配置分布式事务管理器组件。当项目中使用事务时,会通过配置的分布式事务管理器管理分布式事务操作。

实例:

在测试方法上添加 @Transactional 开启事务,然后在两个数据源操作中间模拟抛出异常。

实例:

此时运行测试类,可以发现数据源 1 的事务已回滚,验证成功!

在开发 Spring Boot 项目时,如果默认配置满足不了我们的需求,可以通过手工配置组件实现我们需要的功能。这些组件可能是各个公司提供的,我们根据相应文档,为其配置各个属性即可。

【总结】关于“springboot商城系统教程及源码??”的解读完毕,YSHOP柒贰捌叁商城【系统源码】找客服,更多关于的资讯关注我们!

官网定制、商城开发、小程序开发

柒贰捌叁商城源码

标签: springboot商城系统教程及源码

抱歉,评论功能暂时关闭!

复制成功
微信号: 18988772738
官网制作、商城开发、小程序开发
我知道了