《案例上手 Spring 全家桶》课程亮点

  • 从零掌握 Spring 关键技术
  • 68 讲更全面地覆盖 Spring 全家桶核心模块
  • 100+ 段经典代码示例,快速理解 Spring 全家桶要领
  • 3 大项目实战,掌握 Spring 全家桶实际应用
  • 精选 70 道 Spring 高频面试题评估学习成果
  • 免费赠送 16+ 小时的 Spring 实战视频
  • 进入 Spring 技术社群spring bootspring boot


你能收获什么spring boot

  • 掌握 Spring 全家桶核心模块的实际应用
  • 掌握 Spring Boot Web 开发技术
  • 掌握 Spring Boot 集成常用的关系 / 非关系型数据库
  • 掌握 Spring Cloud 微服务开发技术
  • 掌握更多实际工作中的开发技巧
  • 具备 Java 高级开发的技能要求spring boot


适宜人群spring boot

  • 希望提高技术能力的 Java 开发者
  • 希望全面掌握 Spring 全局核心知识的开发者
  • 面向 Spring 微服务架构项目经验不足的开发者spring boot


前置知识spring boot

  • 熟练掌握 Java 核心基础spring boot
  • 熟练掌握 JavaWeb 后端开发技术spring boot


作者介绍spring boot

宁楠,资深 Java 开发工程师、技术总监,互联网讲师、GitChat 认证作者、《Java 零基础实战》图书作者。有多家大型 IT 企业的从业经历,拥有丰富的软件研发、系统架构经验,热衷于知识分享,乐于将自己的行业经验分享给初学者。spring boot


课程背景spring boot

Spring 是当下 Java 行业的开发标准,企业的招聘信息中也越来越多地出现对于 Spring 技术栈开发能力的要求,可以说 Spring 全家桶已经成为高级 Java 开发人员的必备技能但市面上关于 Spring 全家桶详细全面且实用的内容比较少,尤其对于初学者来讲,学习成本依旧很高。

《案例上手 Spring 全家桶》为初学者提供一站式服务,将 Spring 全家桶的核心模块一次性全部讲清楚,并结合实战案例让读者快速掌握实际开发能力,以输出为结果导向是最高效的学习方法。

希望通过对《案例上手 Spring 全家桶》的学习,让所有需要掌握 Spring 全家桶的读者都能够快速上手,具备使用 Spring 全栈技术进行企业级实战开发的能力成为资深 Java 工程师


课程大纲spring boot

《Spring 全家桶》目录
开篇词:Spring 框架——Java 开发行业的标准
第一部分
Spring 专题
 1-1  Spring 的基本应用——IoC 和 AOP
 1-2  掌握 Spring IoC 两种常规操作,提高工作效率
 1-3  Spring IoC 工厂方法 + 自动装载
 1-4  Spring IoC 基于注解的开发
 1-5  Spring IoC 底层实现
 1-6  Spring 的另一个核心机制 AOP
第二部分
Spring MVC 专题
 2-1  快速搭建第一个 Spring MVC 项目
 2-2  深入探究底层原理,应用更加得心应手
 2-3  Spring MVC 的常用注解
 2-4  搞懂 Spring MVC 数据绑定,让开发更加简单
 2-5  探寻 Spring MVC 视图层的实现机制
 2-6  如何给项目定制数据类型转换器
 2-7  Spring MVC 与主流架构 RESTful 的集成
 2-8  用 Spring MVC 的上传下载机制简化代码
 2-9  数据安全重中之重,Spring MVC 如何处理
 2-10  Spring MVC 表单标签库
 2-11  Spring MVC 国际化
 2-12  JavaWeb 开发的基本操作—EL 表达式
 2-13  EL 表达式的好搭档—JSTL
第三部分
MyBatis 专题
 3-1  速搭建第一个 MyBatis 项目
 3-2  MyBatis 底层实现
 3-3  Mapper.xml 的常用配置
 3-4  MyBatis 逆向工程,简化代码开发
 3-5  MyBatis 延迟加载
 3-6  MyBatis 缓存
 3-7  MyBatis 动态 SQL
 3-8  搭建 Java 常规技术之 SSM 整合
 3-9  Nginx 搭建 Tomcat 集群
第四部分
MongoDB 专题
 4-1  搭建主流 NoSQL MongoDB 环境
 4-2  MongoDB 常用命令
 4-3  Spring Data 集成 MongoDB:MongoTemplate
 4-4  Spring Data 集成 MongoDB:Repository
 4-5  Spring MVC + Layui + Spring Data + MongoDB 项目实战
第五部分
Spring Boot 专题
 5-1  速搭建第一个 Spring Boot 项目
 5-2  Spring Boot 配置文件
 5-3  Spring Boot 整合 JSP
 5-4  Spring Boot 整合 Thymeleaf(上)
 5-5  Spring Boot 整合 Thymeleaf(下)
 5-6  Spring Boot 整合 JdbcTemplate
 5-7  Spring Boot 整合 MyBatis
 5-8  Spring Boot 整合 Spring Data JPA
 5-9  搭建主流 NoSQL Redis 环境
 5-10  Spring Boot 应用中集成 Spring Data Redis
 5-11  Spring Boot 整合 Redis 实现 Session 共享
 5-12  Spring Boot 整合 MongoDB
 5-13  Spring Boot 整合 Spring Security
 5-14  用 Spring Boot 开发一个电商系统
第六部分
Spring Cloud 专题
 6-1  微服务产生的背景
 6-2  搭建微服务系统的核心中枢
 6-3  注册第一个微服务
 6-4  跨服务接口调用神器 RestTemplate
 6-5  微服务调用案例
 6-6  用服务网关统一 URL,开发更简洁
 6-7  Ribbon 负载均衡
 6-8  Spring Cloud Feign 声明式接口调用
 6-9  Hystrix 容错监控机制
 6-10  Spring Cloud Config 本地配置
 6-11  搭建消息中间件 RabbitMQ 环境
 6-12  Spring Cloud Config 远程配置
 6-13  Zipkin 服务跟踪
第七部分
微服务项目实战
 7-1  明确微服务实战项目的详细需求
 7-2  注册中心和配置中心
 7-3  服务提供者 account
 7-4  服务提供者 menu
 7-5  服务提供者 order
 7-6  服务提供者 user
 7-7  服务消费者 clientfeign
* 目前大纲仅供参考,请以实际更新为准

课程内容

开篇词:Spring 框架——Java 开发行业的标准

我是谁

大家好,我叫宁楠,一名撸了多年代码的资深码农,拥有多年软件研发、系统架构经验,历任高级开发工程师 、技术总监。从上大学到现在接触 Java 已有十个年头了,无论是上学期间还是工作之后,身边朋友对我的评价基本是「学习能力强、上手新技术速度快」,这并不是因为我有多聪明,而是需要掌握正确的学习方法。

什么是正确的学习方法?在我看来这个问题要因人而异,我认为好的方法可能并不适用于所有人,每个人都应该找到适合自己的方法。那我的学习方法是什么呢?主要有以下 3 个核心点。

一是我在学习的时候会做深度思考,分析事物的底层原理,并带入到自己当前的学习或工作场景中。比如学到一个新技术,我会思考如果要用它来实现当前的需求,应该怎么做?同时会结合深度思考来做笔记,为了方便查阅,我的笔记都是直接写在书上的,由此,经常会听到借我书看的朋友抱怨:你在书上写那么多字干啥?搞得我都不知道是看你写的字还是看书上的字了,你是没钱买本子吗…

二是学习时一定要以输出结果为目的,我看完书一定要搞出一个成果,可以是一篇技术教程、也可以是一个项目案例。因为只有时刻带着输出结果的思想去学习,才会真正有效,比如写技术教程,首先必须把所有技术点都搞清楚,吸收消化转为自己的东西,然后才能输出。

三是一切以实践为主,我在学习新技术的时候不会把时间花费在理论知识上,首先会大致了解一下技术背景,知道它是做什么的,然后把精力花费在如何使用它,快速实现一个 Demo。这一轮流程走下来,虽说对概念性的内容比较模糊,但是我已经构建起了对技术的直观认知,在此基础上再慢慢打磨细节,就像盖房子,我会先把框架搭起来,再做局部细化,我认为这种方式的效率比较高,至少是适合我的。

一直以来我都在坚持这种学习方法,在学会编程技能的同时也提高了自己深度思考的能力思维认知,对技术的理解一直都在提升,同时也积攒了很多学习笔记,一开始只是自己记,后来开始通过互联网向外输出,比如写博客、公众号等,逐渐积累了一定的读者和关注度,有了一定的影响力之后,就有各种平台抛出合作的橄榄枝,我当然欣然接受,随后就出版了《Java 零基础实战》一书,也输出了一些知识付费内容,包括视频课程和图文课程,比如 GitChat 达人课《案例上手 Spring MVC》。

点击这里了解《Spring 全家桶》

我为什么要写这门课程

什么是 Spring 全家桶

作为一名资深 Java 开发者,与 Spring 打了很多年交道了,真心被这个框架所折服,不光是我,任何一个 Java 开发者都应该有这样的体会。毋庸置疑,Spring 框架目前已经成为 Java 开发行业的标准,Spring 的官方理念也是霸气十足:the source for modern java,意为 Spring 是现代 Java 开发的源头。只要是做 Java 开发的,一定或多或少会接触到 Spring,无论是传统企业还是互联网公司的招聘需求上一定会重点要求具备使用 Spring 框架进行开发的能力。

enter image description here

(图片来自 Spring 官网)

Spring 框架从 2002 年诞生至今经过十多年的发展,已经从最初的取代 EJB 这样一个单一功能发展成为一套完整的生态体系,涉及到现代软件开发的各个方面。

核心模块有哪些

作为开发者并不需要掌握 Spring 的所有模块,但是 Spring Framework、Spring Boot、Spring Cloud 这三大模块是所有 Java 开发者必须要掌握的。

  • Spring Framework 是整个 Spring 生态的基础,各个模块都是基于 Spring Framework 衍生出来的。
  • Spring Boot 是一个快速开发框架,让开发者可以迅速搭建一套基于 Spring 的应用程序,并且将常用的 Spring 模块以及第三方模块,如 MyBatis、Hibernate 等都做了很好的集成,只需要简单的配置即可使用,不需要任何的 XML 配置文件,真正做到了开箱即用,同时默认支持 JSON 格式的数据,使用 Spring Boot 进行前后端分离开发也非常便捷。

enter image description here

(图片来自 Spring 官网)

  • Spring Cloud 是一套整合了分布式应用常用模块的框架,使得开发者可以快速实现微服务应用。作为目前非常热门的技术,有关微服务的话题总是在各种场景下被大家讨论,企业的招聘信息中也越来越多地出现对于微服务架构能力的要求。

enter image description here

(图片来自 Spring 官网)

确实,作为当今互联网时代最先进的业务架构解决方案,微服务发展非常迅速,关注点不仅仅放在开发层面,更多的是开发运维逐步一体的思路。

有些读者可能会认为,我现在就是一个初级程序员,把业务逻辑代码写好就可以了,不需要关心架构层面的东西。这种想法过于片面了,不论你现在处于什么阶段,架构方面的东西早晚都要接触,打个比方,当搬砖对你来说已经驾轻就熟了,这时就需要去思考怎么设计房子,也就是从 CRUD 业务操作到软件设计架构的进阶。

怎样提高自己的软件架构能力呢?首先你要具备扎实的基础知识,第二要有足够的项目经验,第三要视野开阔,技术领域的涉猎面要广。整个学习过程周期是比较长的,需要通过反复的实践,发现问题,解决问题来逐步完善你对于架构的理解,需要沉淀才能到达一定高度,很多之前不理解的东西自然就理解了,因此,从长远角度来看,即使你目前只是一个初级开发者,学习微服务也是非常有必要的。

微服务架构的落地框架有很多,对于 Java 开发者而言,当 Spring 框架已经成为事实上的行业标准时,Spring Cloud 作为 Spring 全家桶的重要一员,自然就是大家的首选,通过横向对比也可以得出结论,Spring Cloud 确实是微服务架构中一个十分优越的解决方案。

初学者的困惑

毫无疑问,Spring 全家桶是当前非常流行的主流框架,也是 Java 开发者的必备技能,无论你是初级菜鸟还是有一定经验的老鸟,都应该好好学习 Spring 全家桶的使用。

但遗憾的是目前市面上有关于 Spring 全家桶详细全面且实用的教程比较少,尤其对于初学者来讲,学习成本依旧很高,主要有以下两方面因素。

(1)目前市面上确实有一些不错的 Spring 课程,但都是分模块讲的,比如只讲 Spring MVC、或只讲 Spring Boot、亦或只讲 Spring Cloud,并没有一个集大成者的系统性课程来帮助初学者一次性搞定所有核心模块,这对初学者来讲是很不利的。要想学完全套 Spring 技术栈,需要同时购买好几个课程,这样成本会比较高,我说的并不是经济成本,而是学习成本,为什么呢?因为不同作者的写作风格是大相径庭的,你在学习 Spring Boot 的时候是按照当前作者的风格进行的,那当学习 Spring Cloud 时又是另外一种风格,在不同类型的教学风格中来回切换思路对于初学者来说不是一件轻松的事儿。

(2)很多课程都侧重于理论讲解,缺乏相应的实战案例,这对于初学者来讲也是挺痛苦的,看似学了很多,真正需要写代码时又不知如何下手,完全没有思路,学了一堆东西却不知道如何应用,那不就背离了我们最初的学习目的了吗?我们学技术就是为了实际应用,提高自己的竞争力,去争取更优质的资源。

我写这门课程就是希望能帮助初学者解决这两个问题,同时提供一站式服务,将 Spring 全家桶的核心模块一次性全部讲清楚,并结合实战案例让读者能够快速掌握实际开发的能力。上面提到过,以输出为结果导向是最高效的学习方法,希望通过我的这门课程,让所有需要掌握 Spring 全家桶的读者都能够快速上手,具备使用 Spring 技术栈进行实际开发的能力。

点击这里了解《Spring 全家桶》

本课程能为你提供哪些价值

在我看来,一门好的课程应该具备以下 4 个特点。

  • 提供新知

这个新知并不一定是新的技术,可以是新的框架版本、新的方法、新的思路、新的项目案例等,因此在本课程中,我们使用的 Spring 全家桶版本都是官方推荐版本(不一定是最新版本,官方推荐的一般都是比较稳定的版本)。

  • 内容全面

本课程重点讲解 Spring 全家桶最核心的 3 个模块:Spring Framework、Spring Boot、Spring Cloud;在此基础上还包括了 Spring Web MVC、Spring Security、Spring Data JPA、Spring Data Redis、Spring Data MongoDB、MyBatis 等框架,以及 MongoDB 数据库、Redis 数据库、Nginx、前端框架 Layui 的使用;同时还包含 3 个项目实战案例,分别是 Spring + Spring MVC + MyBatis + MySQL 电商项目、Spring MVC + Layui + Spring Data + MongoDB 权限管理系统、Layui + Spring Cloud + MyBatis + MySQL 外卖订餐系统,丰富的内容设置以确保读者可以真正学好 Spring 全家桶技术栈并应用于实战。

  • 容易理解

本课程内容深入浅出、通俗易懂,我本人是比较反感长篇大论的讲概念,然后没有多少实际干货的教程。我们学习的目的主要在于应用,而不在于研究理论,因此我的写作风格是偏向于实际应用的,让读者快速掌握 Spring 全家桶各个组件的使用,即使是没有接触过 Spring 框架的初学者也完全可以上手。但也不是完全没有门槛,本课程的学习者必须掌握 Java 核心基础以及 Java Web 开发技能,如果不具备这个条件,建议先学习 Java 基础的内容

  • 售后服务

知识付费产品的售后服务主要是指读者在购买课程后,如果在学习上遇到一些问题,能否及时得到解答,这也是读者比较关心的一个问题,如果做不到这一点,恐怕再好的课程对于初学者来讲也会比较吃力。只要购买了本课程的读者,都可以加入专属读者交流群,我会在群里为大家解决学习过程中遇到的各种问题,争取做到及时、准确地为读者提供在线答疑,用“保姆式”的服务为读者的学习保驾护航。

上述这 4 个特点是我写作这门课程的核心框架和指导方向,力图为读者打造一个学习闭环,一站式解决学习中的各种问题,为读者输出最有价值的内容。

认识一下即将要学习的全家桶成员

  • Spring Framework

Spring Framework 就是我们通常所说的 Spring 框架,它是一个软件设计架构层面的框架,为基于 Java 的企业级应用程序提供了一套标准流程和配置模型,可部署在任何类型的平台上。Spring 优势在于为开发者提供了应用级别的基础结构支持,实现应用层面的解耦合,允许开发者自主选择相关组件,开发者只需专注于业务逻辑的开发,不需要关注特定的部署环境。

  • Spring Web MVC

Spring Web MVC(官方名称)就是我们通常所说的 Spring MVC,它是 Spring Framework 中的一个模块,是 Spring Framework 在 Web 领域实现 MVC 设计模式的具体方案,主要是基于 DispatcherServer 的前端路由处理和 ViewResolver 视图解析器来简化开发者的工作效率。

  • Spring Boot

Spring Boot 是目前 Spring 全家桶系列中最流行的一个产品,在 Spring 官网的介绍排在第一位,可见对其重视程度,Spring 官方对 Spring Boot 的描述是“build anything”,翻译过来是构建任何事物,这样一个非常简单的描述将 Spring Boot 的特点展现的淋漓尽致,即通过 Spring Boot 可以快速构建一个基于 Spring 的独立生存级别的应用程序,开发者直接运行程序即可,无需处理各种繁琐的配置文件。简单理解,Spring Boot 就是为了让开发者快速启动和运行 Spring 应用程序而设计的。

  • Spring Cloud

Spring 官方对 Spring Cloud 的描述是“coordinate anything”,翻译过来是协调任何事物,通过这个描述可以明确 Spring Cloud 并不是为了实现某个业务模块而存在的,它是一个集大成者,将分布式系统开发中常用的模块进行整合,如服务注册、服务发现、配置管理、熔断器、控制总线等,基于 Spring Boot 形成一套框架体系,开箱即用,使得开发者可以快速实现分布式、微服务应用。

  • Spring Data

Spring Data 是 Spring 提供的持久层产品,主要功能是为应用程序中的数据访问提供统一的开发模型,同时保留不同数据存储的特殊性,并且这套开发模式是基于 Spring 的。根据不同类型的数据存储类型又可分为 Spring Data JDBC、Spring Data JPA、Spring Data Redis、Spring Data MongoDB 等,适用于关系型数据库和非关系型数据库。

  • Spring Security

Spring Security 是 Spring 提供的一个功能强大的安全框架,为 Java 应用程序提供授权功能,通过定制身份验证来实现对于访问权限的控制,Spring Security 的特点在于扩展性好,可以根据具体的业务需求来实现定制验证服务。

课程入口:学习者需要具备哪些条件

虽然这门课程我力图做到通俗易懂、深入浅出,让读者可以更加轻松地掌握所有技能,但是毕竟写的是企业级开发框架课程,还是需要读者具备一定基础的,比如:

  • 熟练掌握 Java 核心基础
  • 熟练掌握 Java Web 后端开发技术
  • 对 Spring 框架有基本的了解
  • 渴望全面提高自己的编程能力

课程环境参数

  • macOS Mojave 10.14.5
  • JDK 10.0.1
  • Maven 3.6.1
  • Tomcat 9.0.8
  • IntelliJ IDEA 2019.1
  • Spring Boot 2.1.5
  • Spring Framework 5.1.7
  • Spring Cloud Finchley.RELEASE
  • MySQL 8.0.11
  • MongoDB 4.0.0
  • Redis 4.0.10
  • Nginx 1.16.0
  • RabbitMQ 3.7.10

课程大纲

本课程内容分为七大部分,共计 68 课(含开篇词)。

第一部分:Spring 专题(第 1-1 ~ 1-6 课)

万丈高楼平地起,这部分内容将讲解 Spring Framework 的基本概念、组成,为后面的课程打下基础。

第二部分:Spring MVC 专题(第 2-1 ~ 2-13 课)

这部分内容将详细地讲解 Spring MVC,包括常用模块的使用以及梳理 Spring MVC 的底层实现原理。

第三部分:MyBatis 专题(第 3-1 ~ 3-9 课)

这部分内容将详细讲解主流的 ORMapping 框架 MyBatis,包括常用模块的使用和底层实现原理,作为持久层的实现方案,MyBatis 在实际项目开发中会与 Spring MVC 整合使用。

第四部分:MongoDB 专题(第 4-1 ~ 4-5 课)

这部分内容将详细讲解非关系型数据库 MongoDB 的安装及使用,以及 Spring 全家桶的整合方案 Spring Data MongoDB 的使用,同时完成本套课程的第 2 个项目案例,使用 Spring MVC + Layui + Spring Data MongoDB 实现权限管理系统。

第五部分:Spring Boot 专题(第 5-1 ~ 5-14 课)

重点突破,这部分内容将详细讲解 Spring 全家桶的重头戏——Spring Boot 核心模块的使用,Spring Boot 作为一个快速构建 Spring 应用的利器,对各种主流框架模块做了很好的集成,开箱即用,这部分内容将为大家详细讲解具体操作。

第六部分:Spring Cloud 专题(第 6-1 ~ 6-13 课)

突破重点,这部分内容将详细讲解 Spring 全家桶最热门的模块 Spring Cloud 的使用,包括服务网关、Ribbon、Feign、Hystrix、Spring Cloud Config 等,涵盖了实际开发中常用的技能点,理论结合实践的方式不仅仅让读者掌握基本概念,同时具备使用 Spring Cloud 搭建微服务架构的能力。

第七部分:微服务项目实战(第 7-1 ~ 7-7 课)

上手实战,技能升华。有了前面的 Spring Cloud 基础,这部分内容将详细讲解 Spring Cloud 的实战操作,包括 Spring Cloud 的高可用、集群、负载均衡,以及使用 Layui + Spring Cloud + MyBatis + MySQL 的技术选型来完成本套课程的最终项目实战。

enter image description here

课程出口:Spring Cloud 微服务项目实战

本套课程以开发一个基于 Spring Cloud 的分布式微服务项目为输出结果,如果最终能顺利完成,那么恭喜你,本课程的核心内容已经完全掌握了,如果暂时不能独立完成,那也没关系,继续学习就对了,我会帮助你尽快完成课程出口目标。

来看看我们要做一个什么样的项目,使用 Layui + Spring Cloud + MyBatis + MySQL 的技术选型完成外卖订餐系统,旨在通过这个项目让大家真正掌握 Spring Cloud 各个组件在实际开发中的使用。

本项目分为客户端和后台管理系统两个界面:

  • 客户端针对普通用户,功能包括用户登录、用户退出、菜品订购、我的订单;
  • 后台管理系统针对管理员,功能包括管理员登录、管理员退出、添加菜品、查询菜品、修改菜品、删除菜品、订单处理、添加用户、查询用户、删除用户。

系统架构设计分配出 4 个服务提供者:account、menu、order、user。

  • account 提供账户服务:用户和管理员登录。
  • menu 提供菜品服务:添加菜品、查询菜品、修改菜品、删除菜品。
  • order 提供订单服务:添加订单、查询订单、删除订单、处理订单。
  • user 提供用户服务:添加用户、查询用户、删除用户。

接下来分配出 1 个服务消费者,包括客户端的前端页面和后台接口、后台管理系统的前端页面和后台接口,用户 / 管理员直接访问的资源都保存在服务消费者中,然后服务消费者调用 4 个服务提供者对应的接口完成业务逻辑,并通过 Feign 实现负载均衡。

4 个服务提供者和 1 个服务消费者都需要在注册中心进行注册,同时要注册配置中心,提供远程配置信息读取,服务提供者和服务消费者的配置信息保存在 Git 远程仓库,由配置中心负责拉取。

本系统共由 8 个模块组成,包括注册中心、配置中心、Git 仓库配置信息、服务消费者、4 个服务提供者,关系如下图所示。

enter image description here

成果截图

enter image description here

enter image description here

课程寄语

希望大家学完本课程后,可以明确什么是 Spring 全家桶,以及如何使用 Spring 全家桶的核心模块,并且可以开发出实际项目。我们学习一门技术的目的全在于实际应用,对概念的理解一定要透彻但没必要钻牛角尖,重点是知道它是什么、能干什么以及怎么干,这种以实践为主的方式会贯穿整个课程,我也希望大家能够逐步养成这种编程思想,很多时候当我们真正掌握了一门技术的实际应用并且经过反复实践之后,才能在理论层面上升到一定高度,最重要的是构建自己的体系,这套体系才是你在职场的核心竞争力,预祝学习愉快~

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-4 课末尾添加小助手的微信号,并注明「全家桶」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

温馨提示:需购买才可入群哦,加小助手微信后需要截已购买的图来验证~

点击这里了解《Spring 全家桶》

第 1-1 课:Spring 的基本应用——IoC 和 AOP

前言

对于任何一个 Java 开发人员,Spring 的大名一定如雷贯耳,在行业中可谓是无人不知、无人不晓,说它是 Java 领域第一框架毫不为过。

enter image description here

(图片来自 Spring 官网)

Spring 概念诞生于 2002 年,创始人 Rod Jahnson 在其著作《Expert One-on-One J2EE Design and Development》中第一次提出了 Spring 的核心思想,于 2003 年正式发布第一个版本 Spring Framework 0.9。

经过十几年的优化迭代,Spring Framework 已经从最初的取代 EJB 框架逐步发展为一套完整的生态,最新的版本是 5.X,支持现代 Java 开发的各个技术领域,家族两大核心成员 Spring Boot 和 Spring Cloud 更是当下 Java 领域最为热门的技术栈。

毋庸置疑,Spring 已经成为 Java 开发的行业标准,无论你是初级程序员还是架构师,只要是做 Java 开发的,工作中或多或少一定会接触到 Spring 相关技术栈。

我们所说的 Spring 全家桶各个模块都是基于 Spring Framework 衍生而来,通常所说的 Spring 框架一般泛指 Spring Framework,它包含 IoC 控制反转、DI 依赖注入、AOP 面向切面编程、Context 上下文、bean 管理、Spring Web MVC 等众多功能模块,其他的 Spring 家族成员都需要依赖 Spring Framework。

可以简单理解 Spring Framework 是一个设计层面的框架,通过分层思想来实现组件之间的解耦合,开发者可以根据需求选择不同的组件,并且可以非常方便的进行集成,Spring Framework 的这一特性使得企业级项目开发变得更加简单方便。

Spring 的两大核心机制是 IoC(控制反转)和 AOP(面向切面编程),对于初学者来讲,搞清楚这两个核心机制就掌握了 Spring 的基本应用。这两大核心机制也是 Java 设计模式的典型代表,其中 IoC 是工厂模式,AOP 是代理模式。

点击这里了解《Spring 全家桶》

什么是 IoC 和 AOP

下面来详细了解 IoC,IoC 是 Spring 框架的灵魂,非常重要,理解了 IoC 才能真正掌握 Spring 框架的使用。

IoC 也叫控制反转,首先从字面意思理解,什么叫控制反转?反转的是什么?

在传统的程序开发中,需要获取对象时,通常由开发者来手动创建实例化对象,但是在 Spring 框架中创建对象的工作不再由开发者完成,而是交给 IoC 容器来创建,我们直接获取即可,整个流程完成反转,因此是控制反转。

举个例子:超市购物。

  • 传统方式:你去超市买东西,需要自己拿着袋子去超市购买商品,然后自己把袋子提回来。
  • IoC 容器:你只需要把袋子放在家门口,袋子里面会自动装满你需要的商品,直接取出来用就可以了。

我们通过创建一个 Student 对象的例子来对比两种方式的区别。

传统方式

(1)创建 Student 类

public class Student {    private int id;    private String name;    private int age;}

(2)测试方法中调用构造函数创建对象

Student student = new Student();

IoC 容器

实现步骤
  • 在 pom.xml 中添加 Spring 依赖
  • 创建配置文件,可以自定义文件名 spring.xml
  • 在 spring.xml 中配置 bean 标签,IoC 容器通过加载 bean 标签来创建对象
  • 调用 API 获取 IoC 创建的对象

IoC 容器可以调用无参构造或者有参构造来创建对象,我们先来看无参构造的方式。

无参构造
<!-- 配置 student 对象--><bean id="stu" class="com.southwind.entity.Student"</bean>

配置一个 bean 标签:

  • id,对象名
  • class,对象的模板类

接下来调用 API 获取对象,Spring 提供了两种方式来获取对象:id 或者运行时类。

(1)通过 id 获取对象

//1.加载 spring.xml 配置文件ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");//2.通过 id 值获取对象Student stu = (Student) applicationContext.getBean("stu");System.out.println(stu);

第一步:加载 spring.xml 配置文件,生成 ApplicationContext 对象。

第二步:调用 ApplicationContext 的 getBean 方法获取对象,参数为配置文件中的 id 值。程序在加载 spring.xml 时创建 stu 对象,通过反射机制调用无参构造函数,所有要求交给 IoC 容器管理的类必须有无参构造函数。

运行结果如下图所示。

512e7870-96e4-11e8-9f54-b3cc9167c22b

可以看到,此时 stu 对象的属性全部为空,因为调用无参构造只会创建对象而不会进行赋值,如何赋值呢?只需要在 spring.xml 中进行相关配置即可,如下所示。

<!-- 配置 student 对象 --><bean id="stu" class="com.southwind.entity.Student">    <property name="id" value="1"></property>    <property name="name" value="张三"></property>    <property name="age" value="23"></property></bean>

添加 property 标签:name 对应属性名,value 是属性的值。若包含特殊字符,比如 name="<张三>",使用 \<![CDATA[<张三>]]> 进行配置,如下所示。

<!-- 配置 student 对象 --><bean id="stu" class="com.southwind.entity.Student">   <property name="id" value="1"></property>   <property name="name">       <value><![CDATA[<张三>]]></value>   </property>   <property name="age" value="23"></property></bean>

运行结果如下图所示。

5fcf9670-96e4-11e8-9e0c-8bfb55c56242

Spring 通过调用每个属性的 setter 方法来完成属性的赋值,因此实体类必须有 setter 方法,否则加载时报错,getter 方法可省略。

(2)通过运行时类获取对象

//1.加载 spring.xml 配置文件ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");//2.通过运行时类获取对象Student stu = applicationContext.getBean(Student.class);System.out.println(stu);

此方法有一个弊端,当 spring.xml 中配置两个 Student 的 bean 时程序会抛出异常,因为此时两个 bean 都是由 Student 类生成的,IoC 容器无法将两个 bean 都返回,必须指定一个唯一的 bean。

<bean id="stu" class="com.hzit.entity.Student">   <property name="id" value="1"></property>   <property name="name">       <value><![CDATA[<张三>]]></value>   </property>        <property name="age" value="23"></property></bean><bean id="stu2" class="com.hzit.entity.Student">   <property name="id" value="1"></property>   <property name="name" value="李四"></property>   <property name="age" value="23"></property></bean>

异常信息如下图所示。

6764cf90-96e4-11e8-9f54-b3cc9167c22b

以上是 IoC 容器通过无参构造创建对象的方式,同时 IoC 容器也可以调用有参构造来创建对象。

有参构造

(1)在实体类中创建有参构造

public Student(int id, String name, int age) {        super();        this.id = id;        this.name = name;        this.age = age;}

(2)spring.xml 中进行配置

<!-- 通过有参构造函数创建对象 --><bean id="stu3" class="com.hzit.entity.Student">   <constructor-arg name="id" value="3"></constructor-arg>   <constructor-arg name="name" value="小明"></constructor-arg>   <constructor-arg name="age" value="22"></constructor-arg></bean>

(3)此时 IoC 容器会根据 constructor-arg 标签去加载对应的有参构造函数,创建对象并完成属性赋值。name 的值需要与有参构造的形参名对应,value 是对应的值。除了使用 name 对应参数外,还可以通过下标 index 对应,如下所示。

<!-- 通过有参构造函数创建对象 --><bean id="stu3" class="com.hzit.entity.Student">   <constructor-arg index="0" value="3"></constructor-arg>   <constructor-arg index="1" value="小明"></constructor-arg>   <constructor-arg index="2" value="22"></constructor-arg></bean>

以上是 IoC 容器通过有参构造创建对象的方式,获取对象同样有两种方式可以选择:id 和运行时类。

如果 IoC 容器管理多个对象,并且对象之间有级联关系,如何实现?

(1)创建 Classes 类

public class Classes {    private int id;    private String name;}

(2)在 Student 类中添加 Classes 属性

public class Student {    private int id;    private String name;    private int age;    private Classes classes;}

(3)spring.xml 中配置 classes 对象,然后将该对象赋值给 stu 对象

<!-- 创建 classes 对象 --><bean id="classes" class="com.hzit.entity.Classes">   <property name="id" value="1"></property>   <property name="name" value="Java班"></property></bean><!-- 创建 stu 对象 --><bean id="stu" class="com.hzit.entity.Student">   <property name="id" value="1"></property>   <property name="name">       <value><![CDATA[<张三>]]></value>   </property>   <property name="age" value="23"></property>   <!-- 将 classes 对象赋给 stu 对象 -->   <property name="classes" ref="classes"></property></bean>

再次获取 Student 对象,结果如下图所示。

0d91b450-96e5-11e8-ab3d-7b3c8b8e2dff

在 spring.xml 中,通过 ref 属性将其他 bean 赋给当前 bean 对象,这种方式叫做依赖注入(DI),是 Spring 非常重要的机制,DI 是将不同对象进行关联的一种方式,是 IoC 的具体实现方式,通常 DI 和 IoC 是紧密结合在一起的,因此一般说的 IoC 包括 DI。

如果是集合属性如何依赖注入?

(1)Classes 类中添加 List\<Student> 属性。

public class Classes {    private int id;    private String name;    private List<Student> students;}

(2)spring.xml 中配置 2 个 student 对象、1 个 classes 对象,并将 2 个 student 对象注入到 classes 对象中。

<!-- 配置 classes 对象 --><bean id="classes" class="com.hzit.entity.Classes">   <property name="id" value="1"></property>   <property name="name" value="Java班"></property>   <property name="students">       <!-- 注入 student 对象 -->       <list>           <ref bean="stu"/>           <ref bean="stu2"/>       </list>   </property></bean><bean id="stu" class="com.hzit.entity.Student">   <property name="id" value="1"></property>   <property name="name">        <value><![CDATA[<张三>]]></value>   </property>   <property name="age" value="23"></property></bean><bean id="stu2" class="com.hzit.entity.Student">   <property name="id" value="2"></property>   <property name="name" value="李四"></property>   <property name="age" value="23"></property></bean>

运行结果如下图所示。

1d27e0b0-96e5-11e8-ab3d-7b3c8b8e2dff

集合属性通过 list 标签和 ref 标签完成注入,ref 的 bean 属性指向需要注入的 bean 对象。

总结

这一讲我们讲解了 Spring IoC 的基本概念以及如何使用,IoC 是 Spring 的核心,这很重要。使用 Spring 开发项目时,控制层、业务层、DAO 层都是通过 IoC 来完成依赖注入的。

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-4 课末尾添加小助手的微信号,并注明「全家桶」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

温馨提示:需购买才可入群哦,加小助手微信后需要截已购买的图来验证~

请单击这里下载源码

点击这里了解《Spring 全家桶》

第 1-2 课:掌握 Spring IoC 两种常规操作,提高工作效率

前言

上一讲介绍了 Spring 的 IoC,即控制反转,程序中由 Spring 来管理对象,当需要使用某个对象时,直接通过 IoC 容器来获取对象,并通过 DI 来完成对象之间的注入关系。下面继续来学习 IoC 的相关知识。

Spring 中的 bean

bean 是根据 scope 来生成的,表示 bean 的作用域,scope 有 4 种类型:

  • singleton,单例,表示通过 Spring 容器获取的该对象是唯一的;
  • prototype,原型,表示通过 Spring 容器获取的对象都是不同的;
  • reqeust,请求,表示在一次 HTTP 请求内有效;
  • session,会话,表示在一个用户会话内有效。

后两种只适用于 Web 项目,大多数情况下,我们只会使用 singleton 和 prototype 两种 scope,并且 scope 的默认值是 singleton。

我们通过一个例子来学习这两种配置的区别。

(1)创建 User 实体类

public class User {    private int id;    private String name;    private int age;    public User() {         System.out.println("创建了User对象");    }   }

(2)在 spring.xml 配置 User 的实例化 bean

<bean id="user" class="com.southwind.entity.User">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean>

(3)测试类中通过 Spring 容器获取两个 User 实例化对象 user1 和 user2,并且通过 == 方法判断是否为同一个对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User user = (User) applicationContext.getBean("user");User user2 = (User) applicationContext.getBean("user");System.out.println(user == user2);

运行结果如下图所示。

446b73d0-96e5-11e8-9e0c-8bfb55c56242

看到结果打印 true,并且 User 的构造函数只执行了一次,表示 user1 和 user2 是同一个对象,因此 scope 默认值为 singleton,即默认通过 Spring 容器创建的对象都是单例模式。

修改 spring.xml 中的配置,将 scope 改为 prototype。

<bean id="user" class="com.southwind.entity.User" scope="prototype">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean>

执行代码,结果如下图所示。

50b449f0-96e5-11e8-a80f-e9b555a946c4

可以看到,调用了两次构造函数,并且 == 的结果为 false,表示现在的 user1 和 user2 是两个对象。

点击这里了解《Spring 全家桶》

Spring 的继承

Spring 的继承与 Java 的继承不一样,但思想很相似,子 bean 可以继承父 bean 中的属性。看到这里,你可能会有这样的疑问:子 bean 可以继承父 bean 中的方法吗?

其实这里不存在方法的继承,Spring 的继承是在对象层面进行操作的,即两个 bean 来自同一个类,因此方法是一样的,不存在继承关系,具体使用如下所示。

(1)在 spring.xml 中配置两个 User bean,并建立继承关系。

<bean id="user" class="com.southwind.entity.User">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean><bean id="user2" class="com.southwind.entity.User" parent="user"></bean>

(2)运行代码,结果如下。

User user2 = (User) applicationContext.getBean("user2");System.out.println(user2);

9e5ecbd0-96e5-11e8-9e0c-8bfb55c56242

可以看到,创建了两个 User 对象 user1 和 user2,并且 user2 继承了 user1 的所有属性。user2 在继承 user1 所有属性的基础之上,还可以对属性进行覆盖,直接在 spring.xml 中添加 property 即可。

<bean id="user" class="com.southwind.entity.User">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean><bean id="user2" class="com.southwind.entity.User" parent="user">   <!-- 覆盖 name 属性 -->   <property name="name" value="李四"></property></bean>

再次运行代码,结果如下图所示。

b10d34b0-96e5-11e8-9f54-b3cc9167c22b

name 属性已经被修改为李四,完成覆盖。有读者可能会问,Spring 中的 bean 能不能在不同类之间继承?

答案是可以的,但是需要这两个类的属性列表完全一致,否则会报错,实际开发中并不会使用到这种方式。

Spring 的依赖

与继承类似,依赖也是 bean 和 bean 之间的一种关联方式,配置依赖关系后,被依赖的 bean 一定先创建,再创建依赖的 bean,我们还是通过代码来理解。

(1)创建 Car 实体类

public class Car {    private int id;    private String brand;    public Car() {        System.out.println("创建了Car对象");    }}

(2)在 spring.xml 中配置 User bean、Car bean

<bean id="user" class="com.southwind.entity.User">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean><bean id="car" class="com.southwind.entity.Car">   <property name="id" value="1"></property>   <property name="brand" value="宝马"></property></bean>

(3)测试类中获取两个 bean

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User user = (User) applicationContext.getBean("user");Car car = (Car) applicationContext.getBean("car");

结果如下图所示。

bb27b920-96e5-11e8-a80f-e9b555a946c4

看到结果,先创建 User,后创建 Car,这是由 spring.xml 中 bean 的配置顺序来决定的,先到先得,先配置 User bean,因此先创建了 User 对象。现在修改 spring.xml 配置,User 依赖 Car,设置 depends-on 属性,如下所示。

<bean id="user" class="com.southwind.entity.User" depends-on="car">   <property name="id" value="1"></property>   <property name="name" value="张三"></property>   <property name="age" value="23"></property></bean><bean id="car" class="com.southwind.entity.Car">   <property name="id" value="1"></property>   <property name="brand" value="宝马"></property></bean>

再次运行代码,看到结果,先创建 Car,后创建 User,因为 User 依赖于 Car,所以必须先创建 Car 对象,User 对象才能完成依赖。

c54fab10-96e5-11e8-9e0c-8bfb55c56242

Spring 读取外部资源

在实际开发中,数据库配置一般会保存在 Properties 文件中方便维护,如果使用 Spring 容器来生成数据源对象,如何读取到 properties 配置文件中的内容?

(1)创建 jdbc.properties

driverName = com.mysql.jdbc.Driverurl = jdbc:mysql://localhost:3306/myTest?useUnicode=true&characterEncoding=UTF-8user = rootpwd = root

(2)spring.xml 中配置 C3P0 数据源

<!-- 导入外部的资源文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 创建 C3P0 数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">   <property name="user" value="${user}"></property>   <property name="password" value="${pwd}"></property>   <property name="driverClass" value="${driverName}"></property>   <property name="jdbcUrl" value="${url}"></property></bean>

第一步:导入外部资源文件。

使用 context:property-placeholder 标签,需要导入 context 命名空间。

第二步:通过 ${} 表达式取出外部资源文件的值。

(3)测试类中获取 Spring 创建的 dataSource 对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");DataSource ds = (DataSource) applicationContext.getBean("dataSource");Connection conn = null;try {     conn = ds.getConnection();} catch (SQLException e) {     // TODO Auto-generated catch block     e.printStackTrace();}System.out.println(conn);

(4)运行代码,看到结果,打印 dataSource 对象

d19573f0-96e5-11e8-a80f-e9b555a946c4

除了使用 \<property> 元素为 Bean 的属性装配值和引用外,Spring 还提供了另外一种 bean 属性的装配方式:p 命名空间,该方式进一步简化配置代码。

p 命名空间

p 命名空间可以简化 bean 的各种配置,直接通过代码来学习。

(1)在 User 实体类中添加 Car 属性

public class User {    private int id;    private String name;    private int age;    private Car car;    public User() {        System.out.println("创建了User对象");    }    @Override    public String toString() {        return "User [id=" + id + ", name=" + name + ", age=" + age + ", car="                + car + "]";    }}

(2)spring.xml 中创建 User bean 和 Car bean,并且通过 p 命名空间给属性赋值,同时完成依赖注入,注意需要引入 p 命名间

<bean id="user" class="com.southwind.entity.User" p:id="1" p:name="张三" p:age="23" p:car-ref="car"></bean><bean id="car" class="com.southwind.entity.Car" p:id="1" p:brand="宝马"></bean>

(3)测试类中获取 User 对象,并打印

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User user = (User) applicationContext.getBean("user");System.out.println(user);

运行结果如下图所示,创建了 User 对象和 Car 对象,并且完成属性赋值,以及级联关系。

dae77840-96e5-11e8-a80f-e9b555a946c4

总结

这一讲我们讲解了 Spring IoC 两种常规操作,分别是依赖注入与 p 命名空间,依赖注入是维护对象关联关系的机制。p 命名空间实际上是对配置文件的简化,以提高我们的开发效率。

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-4 课末尾添加小助手的微信号,并注明「全家桶」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

温馨提示:需购买才可入群哦,加小助手微信后需要截已购买的图来验证~

请单击这里下载源码

点击这里了解《Spring 全家桶》

第 1-3 课:Spring IoC 工厂方法 + 自动装载

前言

这一讲我们继续来学习 IoC 的两个常用知识点:IoC 通过工厂方法创建对象、IoC 自动装载(autowire)。

IoC 通过工厂方法创建对象

之前说过 IoC 是典型的工厂模式,下面我们就来学习如何使用工厂模式来创建 bean,IoC 通过工厂模式创建 bean 有两种方式:

  • 静态工厂方法
  • 实例工厂方法

按照惯例,我们还是通过代码来带大家去学习工厂方法,先来学习静态工厂方法。

(1)创建 Car 实体类

public class Car {    private int num;    private String brand;    public Car(int num, String brand) {        super();        this.num = num;        this.brand = brand;    }}

(2)创建静态工厂类、静态工厂方法

public class StaticCarFactory {    private static Map<Integer,Car> cars;    static{        cars = new HashMap<Integer,Car>();        cars.put(1, new Car(1,"奥迪"));        cars.put(2, new Car(2,"奥拓"));    }    public static Car getCar(int num){        return cars.get(id);    }}

(3)在 spring.xml 中配置静态工厂

<!-- 配置静态工厂创建 car 对象 --><bean id="car1" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">   <constructor-arg value="1"></constructor-arg></bean>
  • factory-method 指向静态方法;
  • constructor-arg 的 value 属性为调用静态方法所传的参数。

(4)在测试类中直接获取 car1 对象。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Car car = (Car) applicationContext.getBean("car1");System.out.println(car);

运行结果如下图所示。

eb768390-96e5-11e8-9f54-b3cc9167c22b

点击这里了解《Spring 全家桶》

实例工厂方法

(1)创建实例工厂类、工厂方法

public class InstanceCarFactory {    private Map<Integer,Car> cars;    public InstanceCarFactory() {        cars = new HashMap<Integer,Car>();        cars.put(1, new Car(1,"奥迪"));        cars.put(2, new Car(2,"奥拓"));    }    public Car getCar(int num){        return cars.get(num);    }}

(2)在 spring.xml 中配置 bean

<!-- 配置实例工厂对象 --><bean id="carFactory" class="com.southwind.entity.InstanceCarFactory"></bean><!-- 通过实例工厂对象创建 car 对象 --><bean id="car2" factory-bean="carFactory" factory-method="getCar">    <constructor-arg value="2"></constructor-arg></bean> 

(3)在测试类中直接获取 car2 对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Car car2 = (Car) applicationContext.getBean("car2");System.out.println(car2);

运行结果如下图所示。

f52c52c0-96e5-11e8-ab3d-7b3c8b8e2dff

对比两种方式的区别,静态工厂方法的方式创建 car 对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象即可调用。所以 spring.xml 只需要配置一个 Car bean,而不需要配置工厂 bean。

实例工厂方法创建 car 对象,必须先实例化工厂对象,因为调用的是非静态方法,必须通过对象调用,不能直接通过类来调用,所以 spring.xml 中需要先配置工厂 bean,再配置 Car bean。

其实这里考察的就是静态方法和非静态方法的调用。

IoC 自动装载(autowire)

我们通过前面的学习,掌握了 IoC 创建对象的方式,以及 DI 完成依赖注入的方式,通过配置 property 的 ref 属性,可将 bean 进行依赖注入。

同时 Spring 还提供了另外一种更加简便的方式:自动装载,不需要手动配置 property,IoC 容器会自动选择 bean 完成依赖注入。

自动装载有两种方式:

  • byName,通过属性名自动装载;
  • byType,通过属性对应的数据类型自动装载。

通过代码来学习。

(1)创建 Person 实体类

public class Person {    private int id;    private String name;    private Car car;}

(2)在 spring.xml 中配置 Car bean 和 Person bean,并通过自动装载进行依赖注入。

创建 person 对象时,没有在 property 中配置 car 属性,因此 IoC 容器会自动进行装载,autowire="byName" 表示通过匹配属性名的方式去装载对应的 bean,Person 实体类中有 car 属性,因此就将 id="car" 的 bean 注入到 person 中。

注意:通过 property 标签手动进行 car 的注入优先级更高,若两种方式同时配置,以 property 的配置为准。

<bean id="person" class="com.southwind.entity.Person" autowire="byName">    <property name="id" value="1"></property>   <property name="name" value="张三"></property></bean><bean id="car" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">   <constructor-arg value="2"></constructor-arg></bean>

(3)测试类中获取 person 对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Person person = (Person) applicationContext.getBean("person");System.out.println(person);

运行结果如下图所示。

fec8cd90-96e5-11e8-ab3d-7b3c8b8e2dff

同理,byType 即通过属性的数据类型来配置。

(1)spring.xml 配置如下

<bean id="person" class="com.southwind.entity.Person" autowire="byType">    <property name="id" value="1"></property>   <property name="name" value="张三"></property></bean><bean id="car" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">   <constructor-arg value="1"></constructor-arg></bean><bean id="car2" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">   <constructor-arg value="2"></constructor-arg></bean>

(2)测试类中获取 person 对象

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");Person person = (Person) applicationContext.getBean("person");System.out.println(person);

运行结果如下图所示。

0bc98200-96e6-11e8-9e0c-8bfb55c56242

可以看到控制台直接打印异常信息,这是因为使用了 byType 进行自动装载,但是 spring.xml 中配置了两个 Car bean,IoC 容器不知道应该将哪一个 bean 装载到 person 对象中,所以抛出异常。使用 byType 进行自动装载时,spring.xml 中只能配置一个被装载的 bean。

(3)现修改 spring.xml 配置,只保留一个 bean,如下所示:

<bean id="person" class="com.southwind.entity.Person" autowire="byType">     <property name="id" value="1"></property>    <property name="name" value="张三"></property></bean><bean id="car" class="com.southwind.entity.StaticCarFactory" factory-method="getCar">    <constructor-arg value="1"></constructor-arg></bean>

(4)测试类中获取 person 对象,运行结果如下图所示:

155ad940-96e6-11e8-9f54-b3cc9167c22b

总结

本讲我们讲解了 Spring IoC 的工厂方法与自动装载,工厂方式是 Spring 框架对工厂模式的实现。自动装载是对上一讲内容的依赖注入优化,在维护对象关联关系的基础上,进一步简化配置。

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-4 课末尾添加小助手的微信号,并注明「全家桶」。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

温馨提示:需购买才可入群哦,加小助手微信后需要截已购买的图来验证~

请单击这里下载源码

点击这里了解《Spring 全家桶》

第 2-2 课:深入探究底层原理,应用更加得心应手

前言

上一讲我们学习了 Spring MVC 框架的使用,为了更好地理解这个框架,本讲来仿写一个 Spring MVC 框架,用到的技术比较简单,只需要 XML 解析 + 反射就可以完成,不需要 JDK 动态代理。

自己手写框架的前提是必须理解框架的底层原理和运行机制,因此我们还是先来回顾一下 Spring MVC 的实现原理。

Spring MVC 实现原理

Spring MVC 的核心组件和工作流程的内容具体可以参考第 2-1 讲的内容,通过上一讲的分析,大致可以将 Spring MVC 流程理解如下:

首先需要一个前置控制器 DispatcherServlet,作为整个流程的核心,由它去调用其他组件,共同完成业务。

主要组件有两个:

一是 Controller,调用其业务方法 Method,执行业务逻辑。

二是 ViewResolver 视图解析器,将业务方法的返回值解析为物理视图 + 模型数据,返回客户端。

我们按照这个思路来自己写框架。

点击这里了解《Spring 全家桶》

初始化工作

  • 根据 Spring IoC 容器的特性,需要将参与业务的对象全部创建并保存到容器中,供流程调用。首先需要创建 Controller 对象,HTTP 请求是通过注解找到对应的 Controller 对象,因此我们需要将所有的 Controller 与其注解建立关联,很显然,使用 key-value 结构的 Map 集合来保存最合适不过了,这样就模拟了 IoC 容器。
  • Controller 的 Method 也是通过注解与 HTTP 请求映射的,同样的,我们需要将所有的 Method 与其注解建立关联, HTTP 直接通过注解的值找到对应的 Method,这里也用 Map 集合保存。
  • 实例化视图解析器。

初始化工作完成,接下来处理 HTTP 请求,业务流程如下:

(1)DispatcherServlet 接收请求,通过映射从 IoC 容器中获取对应的 Controller 对象;

(2)根据映射获取 Controller 对象对应的 Method;

(3)调用 Method,获取返回值;

(4)将返回值传给视图解析器,返回物理视图;

(5)完成页面跳转。

思路捋清楚了,接下来开始写代码,我们需要创建下面这四个类:

(1)MyDispatcherServlet,模拟 DispatcherServlet;

(2)MyController,模拟 Controller 注解;

(3)MyRequestMapping,模拟 RequestMapping 注解;

(4)MyViewResolver,模拟 ViewResolver 视图解析器。

首先创建 MyDispatcherServlet,init 方法完成初始化:

(1)将 Controller 与注解进行关联,保存到 iocContainer 中,哪些 Controller 是需要添加到 iocContainer 中的?

必须同时满足两点:

  • springmvc.xml 中配置扫描的类
  • 类定义处添加了注解

注意这两点必须同时满足。

代码思路:

  • 解析 springmvc.xml
  • 获取 component-scan 标签配置包下的所有类
  • 判断这些类若添加了 @MyController 注解,则创建实例对象,并且保存到 iocContainer
  • @MyRequestMapping 的值为键,Controller 对象为值

(2)将 Controller 中的 Method 与注解进行关联,保存到 handlerMapping 中。

代码思路:

  • 遍历 iocContainer 中的 Controller 实例对象
  • 遍历每一个 Controller 对象的 Method
  • 判断 Method 是否添加了 @MyRequestMapping 注解,若添加,则进行映射并保存
  • 保存到 handlerMapping 中,@MyRequestMapping 的值为键,Method 为值

(3)实例化 ViewResolver。

代码思路:

  • 解析 springmvc.xml
  • 根据 bean 标签的 class 属性获取需要实例化的 MyViewResolver
  • 通过反射创建实例化对象,同时获取 prefix 和 suffix 属性,以及 setter 方法
  • 通过反射调用 setter 方法给属性赋值,完成 MyViewResolver 的实例化

doPost 方法处理 HTTP 请求的流程:

(1)解析 HTTP,分别得到 Controller 和 Method 对应的 uri;

(2)通过 uri 分别在 iocContainer 和 handlerMapping 中获取对应的 Controller 及 Method;

(3)通过反射调用 Method,执行业务方法,获取结果;

(4)将结果传给 MyViewResolver 进行解析,返回真正的物理视图(JSP 页面);

(5)完成 JSP 页面跳转。

enter image description here

代码实现

(1)创建 MyController 注解,作用目标为类。

/** * 自定义 Controller 注解 * @author southwind * */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface MyController {    String value() default "";}

(2)创建 MyRequestMapping 注解,作用目标为类和方法。

/** * 自定义 RequestMapping 注解 * @author southwind * */@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface MyRequestMapping {    String value() default "";}

(3)创建 MyDispatcherServlet,核心控制器,init 完成初始化工作,doPost 处理 HTTP 请求。

/** * DispatcherServlet * @author southwind * */public class MyDispatcherServlet extends HttpServlet{    //模拟 IOC 容器,保存 Controller 实例对象    private Map<String,Object> iocContainer = new HashMap<String,Object>();    //保存 handler 映射    private Map<String,Method> handlerMapping = new HashMap<String,Method>();    //自定视图解析器    private MyViewResolver myViewResolver;    @Override    public void init(ServletConfig config) throws ServletException {        // TODO Auto-generated method stub        //扫描 Controller,创建实例对象,并存入 iocContainer        scanController(config);        //初始化 handler 映射        initHandlerMapping();        //加载视图解析器        loadViewResolver(config);    }    /**     * 扫描 Controller     * @param config     */    public void scanController(ServletConfig config){        SAXReader reader = new SAXReader();        try {            //解析 springmvc.xml            String path = config.getServletContext().getRealPath("")+"\\WEB-INF\\classes\\"+config.getInitParameter("contextConfigLocation");               Document document = reader.read(path);            Element root = document.getRootElement();            Iterator iter = root.elementIterator();            while(iter.hasNext()){                Element ele = (Element) iter.next();                if(ele.getName().equals("component-scan")){                    String packageName = ele.attributeValue("base-package");                    //获取 base-package 包下的所有类名                    List<String> list = getClassNames(packageName);                    for(String str:list){                        Class clazz = Class.forName(str);                        //判断是否有 MyController 注解                        if(clazz.isAnnotationPresent(MyController.class)){                            //获取 Controller 中 MyRequestMapping 注解的 value                            MyRequestMapping annotation = (MyRequestMapping) clazz.getAnnotation(MyRequestMapping.class);                            String value = annotation.value().substring(1);                            //Controller 实例对象存入 iocContainer                            iocContainer.put(value, clazz.newInstance());                        }                    }                }            }        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    /**     * 获取包下的所有类名     * @param packageName     * @return     */    public List<String> getClassNames(String packageName){        List<String> classNameList = new ArrayList<String>();        String packagePath = packageName.replace(".", "/");          ClassLoader loader = Thread.currentThread().getContextClassLoader();          URL url = loader.getResource(packagePath);          if(url != null){            File file = new File(url.getPath());              File[] childFiles = file.listFiles();            for(File childFile : childFiles){                String className = packageName+"."+childFile.getName().replace(".class", "");                classNameList.add(className);            }        }        return classNameList;    }    /**     * 初始化 handler 映射     */    public void initHandlerMapping(){        for(String str:iocContainer.keySet()){            Class clazz = iocContainer.get(str).getClass();            Method[] methods = clazz.getMethods();               for (Method method : methods) {                 //判断方式是否添加 MyRequestMapping 注解                 if(method.isAnnotationPresent(MyRequestMapping.class)){                     //获取 Method 中 MyRequestMapping 注解的 value                     MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);                     String value = annotation.value().substring(1);                     //method 存入 methodMapping                     handlerMapping.put(value, method);                 }             }        }    }    /**     * 加载自定义视图解析器     * @param config     */    public void loadViewResolver(ServletConfig config){        SAXReader reader = new SAXReader();        try {            //解析 springmvc.xml            String path = config.getServletContext().getRealPath("")+"\\WEB-INF\\classes\\"+config.getInitParameter("contextConfigLocation");               Document document = reader.read(path);            Element root = document.getRootElement();            Iterator iter = root.elementIterator();            while(iter.hasNext()){                Element ele = (Element) iter.next();                if(ele.getName().equals("bean")){                    String className = ele.attributeValue("class");                    Class clazz = Class.forName(className);                    Object obj = clazz.newInstance();                    //获取 setter 方法                    Method prefixMethod = clazz.getMethod("setPrefix", String.class);                    Method suffixMethod = clazz.getMethod("setSuffix", String.class);                    Iterator beanIter = ele.elementIterator();                    //获取 property 值                    Map<String,String> propertyMap = new HashMap<String,String>();                    while(beanIter.hasNext()){                        Element beanEle = (Element) beanIter.next();                        String name = beanEle.attributeValue("name");                        String value = beanEle.attributeValue("value");                        propertyMap.put(name, value);                    }                    for(String str:propertyMap.keySet()){                        //反射机制调用 setter 方法,完成赋值                        if(str.equals("prefix")){                            prefixMethod.invoke(obj, propertyMap.get(str));                        }                        if(str.equals("suffix")){                            suffixMethod.invoke(obj, propertyMap.get(str));                        }                    }                    myViewResolver = (MyViewResolver) obj;                }            }        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp)            throws ServletException, IOException {        // TODO Auto-generated method stub        this.doPost(req, resp);    }    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp)            throws ServletException, IOException {        // TODO Auto-generated method stub        //获取请求        String handlerUri = req.getRequestURI().split("/")[2];        //获取 Controller 实例        Object obj = iocContainer.get(handlerUri);        String methodUri = req.getRequestURI().split("/")[3];        //获取业务方法        Method method = handlerMapping.get(methodUri);        try {            //反射机制调用业务方法            String value = (String) method.invoke(obj);            //视图解析器将逻辑视图转换为物理视图            String result = myViewResolver.jspMapping(value);            //页面跳转            req.getRequestDispatcher(result).forward(req, resp);        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }     }}

(4)创建视图解析器 MyViewResolver。

/** * 自定义视图解析器 * @author southwind * */public class MyViewResolver {    private String prefix;    private String suffix;    public String getPrefix() {        return prefix;    }    public void setPrefix(String prefix) {        this.prefix = prefix;    }    public String getSuffix() {        return suffix;    }    public void setSuffix(String suffix) {        this.suffix = suffix;    }    public String jspMapping(String value){        return this.prefix+value+this.suffix;    }}

(5)创建 TestController,处理业务请求。

@MyController@MyRequestMapping(value = "/testController")public class TestController {    @MyRequestMapping(value = "/test")    public String test(){        System.out.println("执行test相关业务");        return "index";    }}

(6)测试。

61d14180-9a13-11e8-992f-9dfb28d2b53f

6631dc80-9a13-11e8-992f-9dfb28d2b53f

跳转 index.jsp,同时控制台打印业务日志,访问成功。

总结

本节课我们讲解了 Spring MVC 的底层原理,同时仿照 Spring MVC 手写了一个简单的框架,目的不是让大家自己去写框架,在实际开发中也不需要自己写框架,直接使用成熟的第三方框架即可。手写框架的目的在于让大家更透彻地理解 Spring MVC 的底层流程、学习优秀框架的编程思想,理解了原理,才能更熟练地应用。

分享交流

我们为本课程付费读者创建了微信交流群,以方便更有针对性地讨论课程相关问题。入群方式请到第 1-4 课末尾添加小助手的微信号。

阅读文章过程中有任何疑问随时可以跟其他小伙伴讨论,或者直接向作者提问(作者看到后抽空回复)。你的分享不仅帮助他人,更会提升自己。

温馨提示:需购买才可入群哦,加小助手微信后需要截已购买的图来验证~

请单击这里下载源码

点击这里了解《Spring 全家桶》

第 1-4 课:Spring IoC 基于注解的开发
第 1-5 课:Spring IoC 底层实现
第 1-6 课:Spring 的另一个核心机制 AOP
第 2-1 课:快速搭建第一个 Spring MVC 项目
第 2-3 课:一文学会 Spring MVC 的常用注解
第 2-4 课:搞懂 Spring MVC 数据绑定,让开发更加简单
第 2-5 课:探寻 Spring MVC 视图层的实现机制
第 2-6 课:如何给项目定制数据类型转换器
第 2-7 课:Spring MVC 与主流架构 RESTful 的集成
第 2-8 课:用 Spring MVC 的上传下载机制简化代码
第 2-9 课:数据安全重中之重,Spring MVC 如何处理
第 2-10 课:Spring MVC 表单标签库
第 2-11 课:Spring MVC 国际化
第 2-12 课:Java Web 开发的基本操作之 EL 表达式
第 2-13 课:EL 表达式的好搭档—JSTL
第 3-1 课:搭建第一个 MyBatis 项目
第 3-2 课:MyBatis 底层实现
第 3-3 课:Mapper.xml 的常用配置
第 3-4 课:MyBatis 逆向工程,简化代码开发
第 3-5 课:MyBatis 延迟加载
第 3-6 课:MyBatis 缓存
第 3-7 课:MyBatis 动态 SQL
第 3-8 课:搭建 Java 常规技术之 SSM 整合
第 3-9 课:Nginx 搭建 Tomcat 集群
第 4-1 课:搭建主流 NoSQL MongoDB 环境
第 4-2 课:MongoDB 常用命令
第 4-3 课:Spring Data 集成 MongoDB:MongoTemplate
第 4-4 课:Spring Data 集成 MongoDB:Repository
第 4-5 课:Spring MVC + Layui + Spring Data + MongoDB 项目实战
第 5-1 课:速搭建第一个 Spring Boot 项目
第 5-2 课:Spring Boot 配置文件
第 5-3 课:Spring Boot 整合 JSP
第 5-4 课:Spring Boot 整合 Thymeleaf(上)
第 5-5 课:Spring Boot 整合 Thymeleaf(下)
第 5-6 课:Spring Boot 整合 JdbcTemplate
第 5-7 课:Spring Boot 整合 MyBatis
第 5-8 课:Spring Boot 整合 Spring Data JPA
第 5-9 课:搭建主流 NoSQL Redis 环境
第 5-10 课:Spring Boot 应用中集成 Spring Data Redis
第 5-11 课:Spring Boot 整合 Redis 实现 Session 共享
第 5-12 课:Spring Boot 整合 MongoDB
第 5-13 课:Spring Boot 整合 Spring Security
第 5-14 课:用 Spring Boot 开发一个电商系统
第 6-1 课:微服务产生的背景
第 6-2 课:搭建微服务系统的核心中枢
第 6-3 课:注册第一个微服务
第 6-4 课:跨服务接口调用神器 RestTemplate
第 6-5 课:微服务调用案例
第 6-6 课:用服务网关统一 URL,开发更简洁
第 6-7 课:Ribbon 负载均衡
第 6-8 课:Spring Cloud Feign 声明式接口调用
第 6-9 课:Hystrix 容错监控机制
第 6-10 课:Spring Cloud Config 本地配置
第 6-11 课:搭建消息中间件 RabbitMQ 环境
第 6-12 课:Spring Cloud Config 远程配置
第 6-13 课:Zipkin 服务跟踪
第 7-1 课:明确微服务实战项目的详细需求
第 7-2 课:注册中心和配置中心
第 7-3 课:服务提供者 account
第 7-4 课:服务提供者 menu
第 7-5 课:服务提供者 order
第 7-6 课:服务提供者 user
第 7-7 课:服务消费者 clientfeign
「第一部分:Spring 专题」面试题
「第二部分:Sprint MVC 专题」面试题
「第三部分:MyBatis 专题」面试题
「第四部分:MongoDB 专题」面试题
「第五部分:Spring Boot 专题」面试题
「第六部分:Spring Cloud 专题」面试题
「第七部分:微服务项目实战」

阅读全文: http://gitbook.cn/gitchat/column/5d2daffbb81adb3aa8cab878

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. angular\reac\vue总结

    一、react 1、框架&#xff0c;以它为主导进行开发的js就叫框架&#xff0c;angular就是框架&#xff1b;react就是库,只负责解决你编程中的一些痛点(如数据污染、DOM不能复用等)&#xff0c;它支持组件化开发网站。 2、4个核心思想概念: 为的就是 (1)virtualDOM 虚拟DOM树&…...

    2024/4/20 15:50:00
  2. Vue语法

    Vue语法 1、数据类型分类 第一种划分 基础数据类型&#xff1a;number string boolean复杂数据类型&#xff1a;object ( array function)特殊数据类型&#xff1a;null undefined 第二种划分 初始数据类型&#xff1a;number string boolean null undefined引用数据类型&…...

    2024/4/29 15:30:44
  3. Vue 基础

    模板语法 (1)插值 使用script标签引入&#xff0c;那么会暴露一个 Vue的全局变量 Vue是一个构造器函数 我们要在模板中书写js语法&#xff0c;那么我们使用了一个叫做 mustache 的语法糖&#xff08; 双大括号 &#xff09; 我们将js的语法写在{{}} 里面new Vue的到的实例&a…...

    2024/5/7 16:00:02
  4. vue入门教程(一)

    1. vue简介 1.1 vue是什么 官网&#xff1a;https://cn.vuejs.org/ Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项…...

    2024/4/20 15:49:57
  5. vue基础理论

    Vue基础知识学习 学习一个新的框架&#xff0c;首先先看官方文档&#xff0c;了解如何使用&#xff0c;为什么要使用&#xff0c;它的优点&#xff0c;基本语法 一、vue官方文档&#xff1a; https://cn.vuejs.org/v2/guide/ 二、新手外链vue文件&#xff1a;&#xff08;以…...

    2024/4/21 13:44:11
  6. 双眼皮冷敷要几天

    ...

    2024/4/21 13:44:10
  7. 终于轮到Vue来带给React灵感了?

    终于轮到Vue来带给React灵感了&#xff1f; react-transition-group vue的transition SwitchTransition 用法 注意事项 结束语 react-transition-group 今天在查看react-transition-group的时候&#xff0c;突然发现多出来了一个组件&#xff1a; 咦&#xff1f;奇怪&#…...

    2024/5/7 13:16:17
  8. 全切双眼皮几天能用洗面奶

    ...

    2024/4/21 13:44:10
  9. 哪家双眼皮专选襄阳韩蔻

    ...

    2024/4/21 13:44:07
  10. angular之$parse

    2019独角兽企业重金招聘Python工程师标准>>> 对于 $parse服务&#xff0c;将angular 表达式转换为一个函数 angular.module("MyApp",[]) .controller("MyController", function($scope, $parse){ var context {name: "dreamapple"…...

    2024/4/28 19:28:16
  11. 双眼皮埋线哪家好可认金宪俊

    ...

    2024/4/21 13:44:05
  12. 双眼皮埋线哪个好要问金宪俊

    ...

    2024/4/21 13:44:05
  13. 周口缔莱美整形医院埋线双眼皮多少钱的问金宪俊

    ...

    2024/5/7 17:11:47
  14. 孙欣双眼皮案例

    ...

    2024/4/21 13:44:02
  15. 厦门哪里割双眼皮和开内眼角

    ...

    2024/5/7 15:05:32
  16. 传统方法割昆明做双眼皮价格去到YESTAR

    ...

    2024/4/21 13:44:00
  17. 双眼皮修复便捷襄阳韩蔻

    ...

    2024/4/20 4:16:44
  18. 解析Angularjs的$http异步删除数据及实例

    这篇文章主要介绍了Angularjs的$http异步删除数据详解及实例的相关资料,这里提供实现思路及实现具体的方法&#xff0c;写的十分的全面细致&#xff0c;具有一定的参考价值&#xff0c;对此有需要的朋友可以参考学习下。如有不足之处&#xff0c;欢迎批评指正。 Angularjs的$ht…...

    2024/4/20 15:50:07
  19. 切开双眼皮便捷襄阳韩蔻

    ...

    2024/4/19 21:53:56
  20. AngularJS $http 异步后台无法获取请求参数

    angular在通过异步提交数据时使用了与jquery不一样的请求头部和数据序列化方式,导致部分后台程序无法正常解析数据。 原理分析&#xff08;网上的分析&#xff09;&#xff1a; <span style"font-size:14px;">对于AJAX应用&#xff08;使用XMLHttpRequests&…...

    2024/4/20 15:50:05

最新文章

  1. 【PyTorch单点知识】深入理解与应用转置卷积ConvTranspose2d模块

    文章目录 0. 前言1. 转置卷积概述2. nn.ConvTranspose2d 模块详解2.1 主要参数2.2 属性与方法 3. 计算过程&#xff08;重点&#xff09;3.1 基本过程3.2 调整stride3.3 调整dilation3.4 调整padding3.5 调整output_padding 4. 应用实例5. 总结 0. 前言 按照国际惯例&#xff0…...

    2024/5/7 18:41:02
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/7 10:36:02
  3. 文件输入/输出流(I/O)

    文章目录 前言一、文件输入\输出流是什么&#xff1f;二、使用方法 1.FileInputStream与FileOutputStream类2.FileReader与FileWriter类总结 前言 对于文章I/O(输入/输出流的概述)&#xff0c;有了下文。这篇文章将具体详细展述如何向磁盘文件中输入数据&#xff0c;或者读取磁…...

    2024/5/7 16:00:13
  4. 阿里云8核32G云服务器租用优惠价格表,包括腾讯云和京东云

    8核32G云服务器租用优惠价格表&#xff0c;云服务器吧yunfuwuqiba.com整理阿里云8核32G服务器、腾讯云8核32G和京东云8C32G云主机配置报价&#xff0c;腾讯云和京东云是轻量应用服务器&#xff0c;阿里云是云服务器ECS&#xff1a; 阿里云8核32G服务器 阿里云8核32G服务器价格…...

    2024/5/6 18:16:31
  5. 图像处理相关知识 —— 椒盐噪声

    椒盐噪声是一种常见的图像噪声类型&#xff0c;它会在图像中随机地添加黑色&#xff08;椒&#xff09;和白色&#xff08;盐&#xff09;的像素点&#xff0c;使图像的质量降低。这种噪声模拟了在图像传感器中可能遇到的问题&#xff0c;例如损坏的像素或传输过程中的干扰。 椒…...

    2024/5/5 8:37:08
  6. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/7 5:50:09
  7. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/7 9:45:25
  8. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  9. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/7 14:25:14
  10. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  11. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  12. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  13. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/7 11:36:39
  14. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  15. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  16. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  17. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  18. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/7 9:26:26
  19. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  20. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  21. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  22. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  23. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  24. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  25. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57