diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index edb87652..00000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.* linguist-language=Java diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100755 index 8921b186..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ -"editor.renderWhitespace": true, -"editor.tabSize":4, -"editor.folding": true, -"diffEditor.ignoreTrimWhitespace": true, -"files.trimTrailingWhitespace": true, -"editor.insertSpaces": true -} \ No newline at end of file diff --git a/README.md b/README.md index 9a61c5d3..79984d15 100755 --- a/README.md +++ b/README.md @@ -1,59 +1,66 @@ **`声明`** +本项目为个人学习之总结,内容大多来源网上、书籍、视频,若引用不当,麻烦告知,我定删除。喜欢的话可以`Star`下,生活不易,希望对读者有帮助。祝好!!! -本文档为个人学习的总结,学习的资料大多来源网上、书籍、视频,若引用不当,麻烦告知,我定删除。Issues中记录的为一些面试题。喜欢的话可以`Star`下,生活不易,希望对读者有帮助。祝好!!! +### 目录 -# 目录 +| 英语 | Java生态 | Golang生态 | 中间件 | 持久化 | 服务器 | 网络/系统 | 内功 | 程序人生 | +|:----|:-----|:------|:------|:------|:------|:------|:------|:------| +|英语|Java Basic
JVM
Web
Spring
Spring Boot
Spring Cloud|Go Basic
Go Web|Keepalived
ActiveMQ
RabbitMQ
RocketMQ
MQTT
Netty
Mybatis
Redis
Log|MySQL
Postgresql
Mongodb|Tomcat
Nginx|网络
Linux|数据结构
算法
设计模式|软文
规范
工具
面试集锦
实战训练| -| 英语 | Java | Spring生态 | 中间件 | 数据库 | 服务器 | 架构设计 | 内功 | 网络 | 程序人生 | -|:----|:-----|:------|:------|:------|:------|:------|:------|:------|:-----| -|英语|Basic
JVM
Web
|Spring
Spring Boot
Spring Cloud|Keepalived
ActiveMQ
RabbitMQ
Netty
Mybatis
Redis|MySQL
Postgresql
Mongodb|Tomcat
Nginx
Linux|原则
安全
高可用
扩展性
伸缩性
性能
|数据结构
算法
设计模式|网络|软文
规范
工具
面试集锦
实战训练| - -## 英语 +### 英语 * [计算机行业常用英语积累](tool/english.md) -## Java +### Java * `JavaCore`:  [Java基础](java/basic/java-basic.md)   [JDBC基础](https://github.com/zhonghuasheng/JAVA/blob/master/jdbc/src/main/java/com/zhonghuasheng/jdbc/learn01/BasicSteps.java)  [Java集合](java/basic/java-collection.md)  [Java多线程系列](java/basic/java-thread.md)  [JUC系列](java/basic/java-thread-juc.md)  [Java IO基础](java/basic/java-io-nio.md) * `Java -VM`:  [Java虚拟机系列](java/jvm/深入理解Java虚拟机.md) [JVM虚拟机监控及性能调优系列](java/jvm/JVM虚拟机监控及性能调优.md) * `Java-Web`:  [Servlet基础](java/javaweb/servlet.md) [JSP基础](java/javaweb/jsp.md) -* `Spring X`:  [Spring4基础知识系列](java/spring/spring.md#Spring) [SpringMVC基础知识系列](java/spring/spring.md#SpringMVC) [SpringBoot基础知识系列](java/spring/spring.md#SpringBoot) +* `Spring X`:  [Spring4系列](java/spring/spring.md#Spring) [SpringMVC系列](java/spring/spring.md#SpringMVC) [SpringBoot系列](java/spring/spring.md#SpringBoot) [SpringCloud系列](java/spring/spring-cloud/spring-cloud.md) + +### Golang +* `Golang Basic`:  [Go基础](golang/basic/go-basic.md) +* `Golang Web`:  [Go Web](golang/basic/go-basic.md#goweb) -## 中间件 +### 中间件 * `负载均衡`:  [Keepalived系列](plugins/keepalived.md) -* `消息通信`:  [消息通信基础](http://note.youdao.com/noteshare?id=30a11e46aaef3f00d2ecfb84692ca294&sub=wcp157828038663078) [ActiveMQ系列](plugins/activemq.md) [RabbitMQ系列](plugins/rabbitmq.md)  [Netty系列](plugins/netty.md) -* `数据访问`:  [MyBatis系列](plugins/mybatis.md) +* `消息通信`:  [消息通信基础](http://note.youdao.com/noteshare?id=30a11e46aaef3f00d2ecfb84692ca294&sub=wcp157828038663078) [MQ概述](plugins/mq/mq.md) [ActiveMQ系列](plugins/activemq.md) [RabbitMQ系列](plugins/rabbitmq.md)  [RocketMQ系列](plugins/rocketmq.md)  [Netty系列](plugins/netty.md)  [IOT通信](plugins/mqtt.md) +* `数据访问`:  [MyBatis](plugins/mybatis.md)  [MyBatis-Plus](plugins/mybatis-plus.md) * `数据缓存`:  [Redis系列](plugins/redis.md) -* `搜索引擎`:  [ELK](elasticsearch.md) +* `搜索引擎`:  [Elasticsearch](plugins/elasticsearch.md) +* `日志模块`:  [Log4j2](plugins/log.md) -## 数据库 -* `关系型数据库`:  [数据库理论基础](database/database.md) [MySQL](database/mysql.md) [Postgresql](database/postgresql.md) -* `非关系型数据库`:  [Mongodb学习笔记](database/mongodb.md) +### 数据库 +* `关系型数据库`:  [数据库理论基础](plugins/database/database.md) [MySQL](plugins/mysql.md) [Postgresql](plugins/postgresql.md) +* `非关系型数据库`:  [Mongodb学习笔记](plugins/mongodb.md) -## 服务器 -* [Tomcat服务器](plugins/tomcat.md) [Nginx反向代理服务器搭建](plugins/nginx.md) [Linux系统常用命令](shell/linux.md) +### 服务器 +* [Tomcat服务器](plugins/tomcat.md) [Nginx反向代理服务器搭建](plugins/nginx.md) [Linux系统常用命令](tool/shell/linux.md) -## 架构设计 -* `设计原则`:  [系统设计注意事项](architecture/系统设计注意事项.md) -* `系统安全`:  [系统架构安全设计](architecture/系统架构安全设计.md) -* `高可用性`:  [系统架构高可用设计](architecture/系统架构高可用设计.md) -* `高扩展性`:  [系统架构扩展性设计](architecture/系统架构扩展性设计.md) -* `高伸缩性`:  [系统架构伸缩性设计](architecture/系统架构伸缩性设计.md) -* `系统性能`:  [系统架构性能设计](architecture/系统架构性能设计.md) -* `其他事项`:  [系统架构设计其他注意事项](architecture/系统架构设计其他注意事项.md) +### 架构设计 +* [分布式锁](system/architecture/分布式锁.md) +* [分布式ID生成方案](system/architecture/分布式ID生成方案.md) +* [如何设计一个对外安全的接口](system/architecture/如何设计一个对外安全的接口.md) +* [CAP理论](system/architecture/CAP.md) +* [日志](system/architecture/log-note.md) -## 内功 -* `设计模式`: [23种设计模式](algorithm/设计模式.md) -* `数据结构`: [数据结构系列](algorithm/数据结构.md) -* `算法`: [算法系列](algorithm/algorithm.md) +### 内功 +* `设计模式`: [23种设计模式](system/algorithm/设计模式.md) +* `数据结构`: [数据结构系列](system/algorithm/数据结构.md) +* `算法`: [算法系列](system/algorithm/algorithm.md) +* `操作系统`: [操作系统](tool/shell/linux.md) -## 网络 -* `常见网络问题`: [常见网络问题系列](network/network.md) +### 网络 +* `常见网络问题`: [常见网络问题系列](system/network/network.md) ### 程序人生 > `软文` +* [工作经历 - 记录自己的成长](tool/coding-life.md#记录自己的成长) * [最好的建议](tool/coding-life.md/#最好的建议) * [正视自己的价值](tool/coding-life.md/#正视自己的价值) * [新工程师要干的五件事情](tool/coding-life.md/#新工程师要干的五件事情) +* [为什么CTO,技术总监,架构师不写代码都这么牛逼](http://note.youdao.com/noteshare?id=f4eeda7da9b73adf4294f984a5e7cbe5&sub=945D4467238947AAB5C030B17D5AC01E) +* [技术/管理](https://www.cnblogs.com/yexiaochai/p/14805941.html#top) +* [简单/不简单](https://www.cnblogs.com/xxcanghai/p/ping-shi-de-gong-zuo-ru-he-ti-xian-yi-ge-ren-de-ji.html) > `规范` * [雅虎前端34条军规](http://note.youdao.com/noteshare?id=b59d0da4f7bb2b7ba5f73129d85b1ba1) @@ -63,6 +70,10 @@ * [Java命名规范参考](http://note.youdao.com/noteshare?id=c0ca7331624eb2f19b06f623a1b832ae&sub=2F7223EB9D9E4072B60A1FB578BF0AFA) > `工具` +* [尖刀]() + * [Hutool](tool/hutool.md) +* [Java诊断工具] + * [阿里JAVA诊断工具Arthas](tool/tools.md) * [API测试工具](tool/api-testing-tool.md) * [流量统计,网站分析](tool/common-tools.md) * [日志管理工具](tool/cronolog.md) @@ -84,6 +95,6 @@

技术栈

-![](tutorial-2020-05-18.png) +![](tool/tutorial-2020-10-31.png)
diff --git "a/architecture/\345\276\256\346\234\215\345\212\241.md" "b/architecture/\345\276\256\346\234\215\345\212\241.md" deleted file mode 100755 index f113b278..00000000 --- "a/architecture/\345\276\256\346\234\215\345\212\241.md" +++ /dev/null @@ -1,6 +0,0 @@ -### 学习计划 - -### 学习笔记 -* 微服务定义: 微服务架构就是将一个庞大的业务系统按照业务模块拆分成若干个独立的子系统,每个子系统都是一个独立的应用,它是一种将应用构建成一系列按业务领域划分模块的,小的自治服务的软件架构方式,倡导将复杂的单体应用拆分成若干个功能单一、松偶合的服务,这样可以降低开发难度、增强扩展性、便于敏捷开发,及持续集成与交付活动。 -* 服务治理的概念:所有服务间不允许直接调用,而是先到注册中心进行登记,再由注册中心统一协调和管理所有服务的状态并对外发布,调用者只需要记住服务名称,去找注册中心获取服务即可。 -* 目前国内用的最多的无外乎是两套框架:Dubbo,Spring Cloud。Dubbo大家都很熟悉,从开源到无人维护再到重新冲击Apache顶级项目。但是Dubbo更加准确来说是一个分布式服务框架,致力于提供高效的RPC远程服务调用方案以及SOA服务治理方案。说白了就是个分布式远程服务调用框架。 \ No newline at end of file diff --git "a/architecture/\346\225\260\346\215\256\344\270\255\345\217\260\346\236\266\346\236\204\351\232\217\346\203\263.md" "b/architecture/\346\225\260\346\215\256\344\270\255\345\217\260\346\236\266\346\236\204\351\232\217\346\203\263.md" deleted file mode 100755 index 1b844886..00000000 --- "a/architecture/\346\225\260\346\215\256\344\270\255\345\217\260\346\236\266\346\236\204\351\232\217\346\203\263.md" +++ /dev/null @@ -1,42 +0,0 @@ -### What is the big data platform -> 大数据平台是一个集数据的获取、抽取、整理、计算与服务为一体的平台。 - -### What can be supported by big data platform - -### How to build up a big data platform -#### 数据的采集 -* 数据的采集分历史数据和实时数据,历史数据可以通过脚本来一次性导入数据中台,实时数据需要实时推送到数据中台。 -* 数据采集阶段采用双写来保证数据在传输的过程中会丢失的问题,双写是指写到数据中台和写到日志。 -* 数据采集阶段配置manager: - * 数据接入管理 - * 运营操作管理 - * 指标监控预警 - * 权限管理 - -#### 数据运营 -* 谁在生产数据,谁采集,谁负责,谁授权,谁消费 - -笔记: -2018年年底到2019年年初,一场组织变革的飓风席卷了国内各大互联网公司。阿里、腾讯、百度、京东、美团等先后拿出了几年来最大规模的组织调整计划。 - -在这些变化中,一个值得关注的现象是,各大公司都不约而同地提到了未来转型To B的计划,并在组织架构中增设“中台”,甚至将中台上升为调整的核心方向。 - -多数大公司开展新项目时,都由业务部门先提出需求,信息中心部门进行招标。在这个过程中,每个新系统的上线都意味着一座新的烟囱立起,项目完成后经常遗留下无法计算的重复建设、重复投资、高昂的交互和协作成本。 - -这种烟囱式的系统管理困境,是中国互联网企业发展史上的一个典型问题。 - -数据咨询公司Thoughtworks首席咨询师王健将多数公司的前台和后台形容为两个转速不相协调的齿轮,前台需要快速响应用户需求,后台却追求稳定至上。他对《中国企业家》谈到,中台的功能是将企业的核心能力、数据、用户信息以共享服务的形式加以沉淀,从而解决各业务部门重复造轮子的问题,降低创新成本。 - -落实到具体形态上,中台与平台的最大区别是什么?右军认为,平台的特征是高内聚、低耦合,职责边界清晰、易于集成;而中台在高内聚、低耦合的基础上,更追求数据完整性、业务可运营。 - -全域数据采集与引入:以需求为驱动,以数据多样性的全域思想为指导,采集与引入全业务、多终端、多形态的数据; - -标准规范数据架构与研发:统一基础层、公共中间层、百花齐放应用层的数据分层架构模式,通过数据指标结构化规范化的方式实现指标口径统一; - -连接与深度萃取数据价值:形成以业务核心对象为中心的连接和标签体系,深度萃取数据价值; - -统一数据资产管理:构建元数据中心,通过资产分析、应用、优化、运营四方面对看清数据资产、降低数据管理成本、追踪数据价值。 - -统一主题式服务:通过构建服务元数据中心和数据服务查询引擎,面向业务统一数据出口与数据查询逻辑,屏蔽多数据源与多物理表; - -极大的丰富和完善了阿里巴巴大数据中心,OneData、OneID、OneService渐趋成熟并成为上至CEO、下至一线员工共识的方法论体系。 \ No newline at end of file diff --git "a/architecture/\346\236\266\346\236\204\350\256\276\350\256\241\351\232\217\346\200\235\345\275\225.md" "b/architecture/\346\236\266\346\236\204\350\256\276\350\256\241\351\232\217\346\200\235\345\275\225.md" deleted file mode 100644 index 78c7b9c1..00000000 --- "a/architecture/\346\236\266\346\236\204\350\256\276\350\256\241\351\232\217\346\200\235\345\275\225.md" +++ /dev/null @@ -1,7 +0,0 @@ -### 学习笔记 -* 系统设计的难处在于,业务,成本,性能,三方面都有需求,但是往往不可能都满足。 -* 系统设计注意事项 - 1. 系统设计师要考虑后期对研发阶段、运维阶段的影响。 - 2. 在技术选型上要对技术的细节有较强的掌控力。 - 3. 设计时要带上版本号,为后期升级和线上排查推演提供依据。 -* 微服务是以业务拆分和分布式来应对业务复杂度高和重复开发的问题 \ No newline at end of file diff --git "a/architecture/\347\263\273\347\273\237\346\236\266\346\236\204\345\256\211\345\205\250\350\256\276\350\256\241.md" "b/architecture/\347\263\273\347\273\237\346\236\266\346\236\204\345\256\211\345\205\250\350\256\276\350\256\241.md" deleted file mode 100644 index b5f7216f..00000000 --- "a/architecture/\347\263\273\347\273\237\346\236\266\346\236\204\345\256\211\345\205\250\350\256\276\350\256\241.md" +++ /dev/null @@ -1,2 +0,0 @@ -[如何设计一个对外安全的接口](如何设计一个对外安全的接口.md) -TODO[反爬虫] \ No newline at end of file diff --git a/bigdata/bigdata.md b/bigdata/bigdata.md deleted file mode 100644 index 3f194822..00000000 --- a/bigdata/bigdata.md +++ /dev/null @@ -1,5 +0,0 @@ -### 学习计划 -* MongoDB+Spark完整的大数据解决方案 http://note.youdao.com/noteshare?id=7176c9c2ef60cea55f3d4b41e1912388&sub=wcp1579254617339255 -* SpringBoot集成Spark https://my.oschina.net/woter/blog/1843755 - -### 学习笔记 \ No newline at end of file diff --git a/frontend/vue.md b/frontend/vue.md deleted file mode 100644 index 1d27b27e..00000000 --- a/frontend/vue.md +++ /dev/null @@ -1,3 +0,0 @@ -* vue是一个渐进式框架:渐进式是按需添加依赖的模块,而不是全部都拿过来 -* 响应式:vue中的Databindings让前端能够实时因数据的改变而改变 -* Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统 \ No newline at end of file diff --git a/golang/basic/go-100-questions.md b/golang/basic/go-100-questions.md new file mode 100644 index 00000000..fb57b30e --- /dev/null +++ b/golang/basic/go-100-questions.md @@ -0,0 +1,5 @@ +# Go白问 +1. 使用go关键字开启一个协程都发生了什么?它与java中的并发有什么不一样的地方? +```go +go count(5) // 使用go关键字创建一个goroutine +``` \ No newline at end of file diff --git a/golang/basic/go-basic.md b/golang/basic/go-basic.md new file mode 100644 index 00000000..cf6f2b04 --- /dev/null +++ b/golang/basic/go-basic.md @@ -0,0 +1,88 @@ +### 学习计划 +* B站8小时转go开发 +* go-kit实战小例子 + +#### go basic + +#### go web +* 示例地址 https://github.com/zhonghuasheng/JAVA_LOVE_GO/tree/master/gop/com/zhonghuasheng/web + +### 目录 +* RPC +* Protobuf +* go thinking +* basic +* 空白标识符 +* 注意 + +### RPC +整体过程就是: +1. 客户端发送数据(以字节流的方式) +2. 服务端接收并解析。根据约定知道执行什么,然后把结果返回客户端 +RPC就是把 +1. 上述流程封装下,使其操作更加优化,让使用者感觉像是调用本地方法一样 +2. 使用一些大家都认可的协议 使其规范化 +3. 做成一些框架,直接或间接产生利益 + +### Protobuf +Google Protocol Buffer +轻便高效的序列化数据结构协议 + +### go thinking +众多语言学术流派,面向过程、面向对象、函数式编程、面向消息编程等。Go语言接受函数式编程、支持匿名函数与闭包,接受以Erlang语言为代表的面向消息编程思想,支持goroutine和通道,并推荐使用消息而不是共享内存来进行并发编程。Go语言最主要的特性 +* 自动垃圾回收 +* runtime系统调度机制 +* 更丰富的内置类型 +* 函数多返回值 +* 错误处理 +* 匿名函数和闭包 +* 类型和接口 +* 并发编程 +* 反射 +* 语言交互性 + +### basic +* Go程序由多个标记组成,可以是关键字、标识符、常量、字符串、符号。 + * 行分隔符: 每一行代表一个语句结束。建议每一行加上分号;标识结尾,不加的话Go编译器自动完成 + * 注释:注释不会被编译 + * 标识符:标识符用来命名变量、类型等程序实体 + * 字符串连接:Go语言的字符串可以通过+实现 + * 关键字:Go语言包含25个关键字。break default func interface select case defer go map struct chan else goto package switch const flatthrough if range type continue for import return var + * Go语言还有36个预定义标识符 +* 空白标识符_是一个只写变量,你不能得到它的值,被用于抛弃值。这样做是因为Go语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。 +* 环境搭建 + * windows环境搭建 + * 安装go二进制文件 到镜像网站下载 https://goproxy.io/zh/ + * 下载Goland IDEA,设置GOPATH + * 配置GOPROXY代理,不然很慢 + * go get xxx 下载xxx包 + * go mod tidy 刷新 类似maven update +* go三层经典模型 + * Transport 主要负责Http, gRpc, thrift + * Services 业务函数 + * Endpoint 定义request, response格式等 +* 四种变量声明方式 +* channel,go语言是如何实现不同协程之前通信的呢?其他语言是通过共享内存来实现通信,而go语言是通过通信来实现共享。一个重要的特性:不论是从channel中读一条消息,还是往channel中发送一条消息,都会阻塞当前代码运行。 + +##### 指针 +取址运算符“&”用于获取对象地址。 +指针运算符“*”用于间接引用目标对象。 +```code +x := 10 +var p *int = &x // 获取地址,保存到指针变量 +*p += 20 // 用指针间接引用,并更新对象 +``` + +### 注意 +* go语言中{不能单独放在一行,否则运行时会产生错误 + +### 其他 +* facebook grace平滑升级项目 +* 腾讯在15年的时候使用go做了docker万台规模,主要用于蓝鲸游戏平台 + +### 常见错误 +* package command-line-arguments is not a main package +要运行的go文件,package不是main。PS,也要有一个main函数 + +* sql: Scan error on column index 3, name "created_at": unsupported Scan, storing driver.Value type []uint8 into type *time.Time +在conn上加parseTime=true,eg `/guestdb?charset=utf8&parseTime=true` \ No newline at end of file diff --git a/golang/basic/go-question.md b/golang/basic/go-question.md new file mode 100644 index 00000000..67360975 --- /dev/null +++ b/golang/basic/go-question.md @@ -0,0 +1,111 @@ +# Go语言答疑解惑 + +## channel +* 从一个关闭的 channel 仍然能读出数据吗 +* channel 有哪些应用 +* 如何优雅地关闭 channel +* channel 在什么情况下会引起资源泄漏 +* 什么是 CSP +* channel 底层的数据结构是什么 +* channel 发送和接收元素的本质是什么 +* 关于 channel 的 happened-before 有哪些 +* 向 channel 发送数据的过程是怎样的 +* 从 channel 接收数据的过程是怎样的 +* 操作 channel 的情况总结 +* 关闭一个 channel 的过程是怎样的 + +## map +* map 的底层实现原理是什么 +* 可以边遍历边删除吗 +* map 的删除过程是怎样的 +* 可以对 map 的元素取地址吗 +* 如何比较两个 map 相等 +* 如何实现两种 get 操作 +* map 是线程安全的吗 +* map 的遍历过程是怎样的 +* map 中的 key 为什么是无序的 +* float 类型可以作为 map 的 key 吗 +* map 的赋值过程是怎样的 +* map 的扩容过程是怎样的 + +## interface +* iface 和 eface 的区别是什么 +* Go 接口与 C++ 接口有何异同 +* 接口转换的原理 +* 如何用 interface 实现多态 +* Go 语言与鸭子类型的关系 +* 值接收者和指针接收者的区别 +* 接口的构造过程是怎样的 +* 编译器自动检测类型是否实现接口 +* 类型转换和断言的区别 +* 接口的动态类型和动态值 + +## 标准库 +* context 如何被取消 +* context 是什么 +* context 有什么作用 +* context.Value 的查找过程是怎样的 +* unsafe +* Go指针和unsafe.Pointer有什么区别 +* 如何利用unsafe包修改私有成员 +* 如何利用unsafe获取slice&map的长度 +* 如何实现字符串和byte切片的零拷贝转换 + +## goroutine 调度器 +* g0 栈何用户栈如何切换 +* goroutine 如何退出 +* goroutine 调度时机有哪些 +* goroutine和线程的区别 +* GPM 是什么 +* M 如何找工作 +* mian gorutine 如何创建 +* schedule 循环如何启动 +* schedule 循环如何运转 +* sysmon 后台监控线程做了什么 +* 一个调度相关的陷阱 +* 什么是 go shceduler +* 什么是M:N模型 +* 什么是workstealing +* 描述 scheduler 的初始化过程 + +## 编译和链接 +* Go 程序启动过程是怎样的 +* Go 编译相关的命令详解 +* Go 编译链接过程概述 +* GoRoot 和 GoPath 有什么用 +* 逃逸分析是怎么进行的 + +## 反射 +* Go 语言中反射有哪些应用 +* Go 语言如何实现反射 +* 什么情况下需要使用反射 +* 什么是反射 +* 如何比较两个对象完全相同 + +## 数组与切片 +* 切片作为函数参数 +* 切片的容量是怎样增长的 +* 数组和切片有什么异同 + + +## GC 的认识 +* 什么是 GC,有什么作用? +* 根对象到底是什么? +* 常见的 GC 实现方式有哪些?Go 语言的 GC 使用的是 +* 三色标记法是什么? +* STW 是什么意思? +* 如何观察 Go GC? +* 有了 GC,为什么还会发生内存泄露? +* 并发标记清除法的难点是什么? +* 什么是写屏障、混合写屏障,如何实现? +* Go 语言中 GC 的流程是什么? +* 触发 GC 的时机是什么? +* 如果内存分配速度超过了标记清除的速度怎么办? +* GC 关注的指标有哪些? +* Go 的 GC 如何调优? +* Go 的垃圾回收器有哪些相关的 API?其作用分 +* Go 历史各个版本在 GC 方面的改进? +* Go GC 在演化过程中还存在哪些其他设计?为什么没有被采用? +* 目前提供 GC 的语言以及不提供 GC 的语言有哪些?GC 和 No GC 各自的优缺点是什么? +* Go 对比 Java、V8 中 JavaScript 的 GC 性能如何? +* 目前 Go 语言的 GC 还存在哪些问题? diff --git a/algorithm/algorithm.md b/java/basic/draw.drawio similarity index 100% rename from algorithm/algorithm.md rename to java/basic/draw.drawio diff --git a/java/basic/hashmap.md b/java/basic/hashmap.md new file mode 100644 index 00000000..89b969f9 --- /dev/null +++ b/java/basic/hashmap.md @@ -0,0 +1,14 @@ +### 学习笔记 +Hash几乎是面试的必考,我没事就找机会面试,几乎每次都被面到,面试的时候主要是考察你对Hash底层结构的理解,同时结合你项目实际中的使用来聊。我在这些年的开发和研发过程中,确实有很多场景的设计或者使用都或多或少用到了Hash,当然平时开发写代码,肯定少不了HashMap。面试官还喜欢问你对JDK7和8中HashMap的区别,也可以看看我的[面试宝典](../../tool/interview.md#盘涅) + +* HashMap 全理论 https://blog.csdn.net/weixin_34392227/article/details/112348756 +* HashMap面试题 https://www.cnblogs.com/aobing/p/12014271.html +* HashMap JDK8以前头插法为什么会出现死循环 https://www.bilibili.com/video/BV1n541177Ea?spm_id_from=333.337.search-card.all.click + + +### 为什么链表长度达到8后变为红黑树 +https://www.pianshen.com/article/2770135206/ + + +### HashMap基础知识 +* [一致性Hash](http://note.youdao.com/noteshare?id=2df0dfa390855dde55075260b8ddc27a&sub=A2CDBD1C8B614310ABFF0F03682FAB7A) \ No newline at end of file diff --git a/java/basic/img/executor-service.png b/java/basic/img/executor-service.png new file mode 100644 index 00000000..c0470f80 Binary files /dev/null and b/java/basic/img/executor-service.png differ diff --git a/java/basic/java-basic.md b/java/basic/java-basic.md index 5f53b3ff..c333d348 100755 --- a/java/basic/java-basic.md +++ b/java/basic/java-basic.md @@ -1,3 +1,4 @@ +## 目录 * [一、数据类型](#一数据类型) * [基本类型](#基本类型) * [包装类型](#包装类型) @@ -35,9 +36,10 @@ * [Java 各版本的新特性](#java-各版本的新特性) * [Java 与 C++ 的区别](#java-与-c-的区别) * [JRE or JDK](#jre-or-jdk) + * [Lambda表达式](#Lambda表达式) * [参考资料](#参考资料) - +## 面试题 # 一、数据类型 @@ -1187,7 +1189,8 @@ System.out.println(e2.get(2)); // 2 `transient` 将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化。【对象序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序;从字节流创建对象的相反的过程称为反序列化】 - +为什么要不序列化? + 一些敏感信息,比如密码和银行卡号等在java对象序列化时不希望被序列化,不被序列化的属性就不会被存储到磁盘上,或通过网络传输。为了实现属性不被序列化,只需要在属性前加上transient关键字就能达到目的。 `volatile` volatile只能修饰变量,被修饰的变量对其他线程是“可见的”,同时volatile修饰的变量禁止指令重排(保证了有序性) @@ -1532,6 +1535,21 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译 - JRE is the JVM program, Java application need to run on JRE. - JDK is a superset of JRE, JRE + tools for developing java programs. e.g, it provides the compiler "javac" +## Lambda表达式 +Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。 +Java 中的 Lambda 表达式通常使用 `(argument) -> (body)` 语法书写,例如: +```java +(arg1, arg2...) -> { body } +(type1 arg1, type2 arg2...) -> { body } + + +(int a, int b) -> { return a + b; } +() -> System.out.println("Hello World"); +(String s) -> { System.out.println(s); } +() -> 42 +() -> { return 3.1415 }; +``` + # 参考资料 - Eckel B. Java 编程思想[M]. 机械工业出版社, 2002. @@ -1557,4 +1575,31 @@ https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html ### 集合框架 ### 异常处理 ### JAVA8新特性 -### JAVA8新特性 \ No newline at end of file +### JAVA8新特性 + +## 面试题 +* Integer和int的区别 +* String a = new String("abc");共创建了几个对象 + +## 注意点 +1. BigDecimal比较值,不要使用equals,因为0和0.00比较equals会判断false,要使用compareTo()。Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. +2. String.split()在分割. |等时需要注意,因为split分割的时候使用了正则, 点需要使用\\.类处理,具体使用时百度下 +3. 邮箱校验 建议使用微软的格式规范 https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/how-to-verify-that-strings-are-in-valid-email-format +``` +^[^@\s]+@[^@\s]+\.[^@\s]+$ +^ 从字符串的开头部分开始匹配。 +[^@\s]+ 匹配一次或多次出现的任何字符,@ 字符或空格除外。 +@ 匹配 @ 字符。 +[^@\s]+ 匹配一次或多次出现的任何字符,@ 字符或空格除外。 +\. 匹配一个句点字符。 +[^@\s]+ 匹配一次或多次出现的任何字符,@ 字符或空格除外。 +$ 在字符串的结尾结束匹配。 +``` +4. 获取系统临时目录 File tmpdir = new File(AccessController.doPrivileged(new GetPropertyAction("java.io.tmpdir"))); AccessController.doPrivileged中断了栈检查过程,使得后续原本没有权限的代码也可以正常执行 https://blog.csdn.net/jiangtianjiao/article/details/87909065 +5. ParserConfig.getGlobalInstance().setAutoTypeSupport(true); 用于解决fastjson漏洞,防止被远程执行 +6. 动态监控JVM内存,并触发gc,可弄个定时任务 +```java +long totalMemory = Runtime.getRunTime().totalMemory() / 1024 /1024; +long freeMemory = Runtime.getRunTime().freeMemory() / 1024 /1024; +System.gc(); // 可触发gc +``` \ No newline at end of file diff --git a/java/basic/java-collection.md b/java/basic/java-collection.md index 832b7f8a..4fb2b264 100755 --- a/java/basic/java-collection.md +++ b/java/basic/java-collection.md @@ -42,6 +42,7 @@ * [Collections工具类-操作集合]() * [Arrays工具类-操作数组]() * [5. 圈重点](#5.圈重点) +* [6. Stream](#6.Stream) * [参考资料](#参考资料) @@ -119,8 +120,30 @@ Map 映射顺序。有些实现类,可以明确保证其顺序,如 TreeMap Map 的实现类应该提供2个“标准的”构造方法:第一个,void(无参数)构造方法,用于创建空映射;第二个,带有单个 Map 类型参数的构造方法,用于创建一个与其参数具有相同键-值映射关系的新映射。实际上,后一个构造方法允许用户复制任意映射,生成所需类的一个等价映射。尽管无法强制执行此建议(因为接口不能包含构造方法),但是 JDK 中所有通用的映射实现都遵从它。 ``` -[Map的三种Collection视图例子 MapTest01.java](https://github.com/zhonghuasheng/JAVA/blob/master/basic/src/main/java/com/zhonghuasheng/basic/util/MapTest01.java) +[Map的三种Collection视图例子 MapTest01.java] +```java + // key视图 + Set keys = hashMap.keySet(); + Iterator iteratorKeys = keys.iterator(); + while (iteratorKeys.hasNext()) { + System.out.println(iteratorKeys.next()); + } + + // value视图 + Collection values = hashMap.values(); + Iterator iteratorValues = values.iterator(); + while (iteratorValues.hasNext()) { + System.out.println(iteratorValues.next()); + } + // key-value视图 + Set> entrySets = hashMap.entrySet(); + Iterator> iteratorEntrySets = entrySets.iterator(); + while (iteratorEntrySets.hasNext()) { + Entry entry = iteratorEntrySets.next(); + System.out.println(String.format("key: %s, value: %s", entry.getKey(), entry.getValue())); + } +``` ## Concurrent包下的集合概述 1. 概述 @@ -491,7 +514,7 @@ AbstractSet没有对Set做多少的实现,其继承了AbstractCollection `总结` ``` HashSet是一个没有重复元素的集合,它是由HashMap实现的(HashMap中key不能重复),不保证元素的顺序,而且HashSet允许使用null元素。 -HashSet是非同步的,因此如果多线程同时访问一个HashSet,而其中至少有一个线程修改了该HashSet夺得话,那么需要保持外部同步,通常可以对该Set的对象封装来完成同步操作,也可以使用Collections.synchronizedSet方法来完成。 +HashSet是非同步的,因此如果多线程同时访问一个HashSet,而其中至少有一个线程修改了该HashSet的话,那么需要保持外部同步,通常可以对该Set的对象封装来完成同步操作,也可以使用Collections.synchronizedSet方法来完成。 HashSet是通过Iterator迭代遍历的 ``` @@ -1123,6 +1146,12 @@ List list = Arrays.asList(1, 2, 3); * Collection集合用于存Object的,不支持存储基础数据类型,这是由Collection接口的定义决定的: Collection * iterator.remove()方法必须要在调用了next()方法之后,否则会报IllegalStateException +# 6.Stream +* List转map,按某个字段分类 +```java + // group by City + Map> employeesByCity = employees.stream().collect( Collectors.groupingBy(Employee::getCity)); +``` # 参考资料 * 集合框架图 https://img-blog.csdn.net/20160124221843905 diff --git a/java/basic/java-thread-juc.md b/java/basic/java-thread-juc.md index 02eea984..a88cb76f 100644 --- a/java/basic/java-thread-juc.md +++ b/java/basic/java-thread-juc.md @@ -1,4 +1,5 @@ # 目录 +* [为什么要AQS?](#为什么要AQS) * [Java为什么会有并发问题](#Java为什么会有并发问题) * [什么是CAS](#什么是CAS) * [Unsafe类解读](#Unsafe类解读) @@ -7,6 +8,10 @@ * [基础类型AtomicInteger](#基础类型AtomicInteger) * [线程池](#线程池) + +## 为什么要AQS +AQS(Abstracting Queue Sychronizer),望文生义,即一个抽象队列 + 一个需要同步的状态,所谓抽象队列即这个队列并不是真是存在的(通俗的讲,不是一个LinkedList对象),而是像HashMap中的链表一样,只存在Node之间的关系中,每个Node负责维护前置与后置节点,以及持有一个请求线程(可以理解为将一个请求线程封装成Node); +http://chpf.rongsoft.com/article/2020/02/18101645580/ ## Java为什么会有并发问题 > 出现的原因 因为Java是一种多线程的处理模型。所以当一个请求过来的时候,Java会将产生一个线程来处理这个请求。如果多个线程访问同一个共享变量的时候,就会出现并发问题。所以,并发问题产生的条件之一是“共享变量”。那么什么样的变量是共享变量呢?这就涉及到Java内存模型JMM了,Java内存模型中,一个Java线程,要想获取到一个变量,需要先将变量从主内存放入工作内存,然后再通过工作内存获取,经历一个lock->read->load->use的过程。每一个线程都有这样一个过程才能获取到变量,这样自然就有可能出现A线程获取到变量,还未赋值回主内存,就被B线程读取或更改的场景,这样自然就会出现不一致问题。 diff --git a/java/basic/java-thread.md b/java/basic/java-thread.md index 3fe230d2..19062975 100644 --- a/java/basic/java-thread.md +++ b/java/basic/java-thread.md @@ -18,6 +18,8 @@ * [生产者消费者问题](#生产者消费者问题) * [钩子线程](#钩子线程) * [线程中的异常](#线程中的异常) +* [线程池](#线程池) +* [建议](#建议) ### 基础概念 @@ -598,6 +600,15 @@ public final synchronized void join(long millis) while(isAlive())是为了防止子线程伪唤醒(spurious wakeup),只要子线程没有TERMINATED的,父线程就需要继续等下去。 5. join() 和 sleep() 一样,可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。 +```java +thread1.start(); +thread1.join(); +thread2.start(); +thread2.join(); +thread3.start(); +thread3.join(); +``` +调用线程的wait()方法时,会使主线程处于等待状态,等待子线程执行完成后再次向下执行。也就是说,在ThreadSort02类的main()方法中,调用子线程的join()方法,会阻塞main()方法的执行,当子线程执行完成后,main()方法会继续向下执行,启动第二个子线程,并执行子线程的业务逻辑,以此类推 ### 线程的中断interrupted interrupt()的作用是中断本线程。 本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。 @@ -759,6 +770,73 @@ public class UncaughtExceptionExample { } ``` +核心线程(corePool):线程池最终执行任务的角色肯定还是线程,同时我们也会限制线程的数量,所以我们可以这样理解核心线程,有新任务提交时,首先检查核心线程数,如果核心线程都在工作,而且数量也已经达到最大核心线程数,则不会继续新建核心线程,而会将任务放入等待队列。 + +等待队列 (workQueue):等待队列用于存储当核心线程都在忙时,继续新增的任务,核心线程在执行完当前任务后,也会去等待队列拉取任务继续执行,这个队列一般是一个线程安全的阻塞队列,它的容量也可以由开发者根据业务来定制。 + +非核心线程:当等待队列满了,如果当前线程数没有超过最大线程数,则会新建线程执行任务,那么核心线程和非核心线程到底有什么区别呢?说出来你可能不信,本质上它们没有什么区别,创建出来的线程也根本没有标识去区分它们是核心还是非核心的,线程池只会去判断已有的线程数(包括核心和非核心)去跟核心线程数和最大线程数比较,来决定下一步的策略。 + +### 线程池 +Executor框架是指java5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService, +CompletionService,Future,Callable等。并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe)。Executor在执行时使用内部的线程池完成操作。 + +![](img/executor-service.png) + +#### 创建线程池常用的类 +* Executors.newCachedThreadPool: 创建一个可缓存的线程池 +* Executors.newFixedThreadPool: 创建一个定长的线程池,可以控制线程的最大并发数,超出的线程会在队列中等待 +* Executors.newScheduledThreadPool: 创建一个定长的线程池,支持定时、周期性的任务执行 +* Executors.newSingleThreadExecutor: 创建一个单线程的线程池,使用一个唯一的工作线程执行任务,保证所有任务按照指定顺序执行 +* Executors.newSingleThreadScheduledExecutor: 创建一个单线程的线程池,支持定时、周期性的任务执行 +* Executors.newWorkStealingPool: 创建一个具有并行级别的work-stealing线程池 +> 参数 +* corePoolSize: 核心线程数量 +* maximumPoolSize: 最大线程数 +* workQueue: 阻塞队列,存储等待执行的任务 +线程池任务执行的主要工作流程: +1. 如果运行的线程数小于corePoolSize,直接创建新线程处理任务,即使线程池中的其他线程是空闲的 +2. 如果运行的线程数大于等于cordPoolSize,并且小于maximumPoolSize,则将此任务放入队列workQueue,如果workQueue满并且正在运行的线程数量小于maximumPoolSize,才会创建新的非核心线程处理任务 +3. 如果运行的线程数量大于等于maximumPoolSize,同时,workQueue已经满了,会通过拒绝策略参数rejectHandler来指定处理策略 +4. 当一个线程完成任务时,它会从队列中取下一个任务来执行。 +5. 当一个线程空闲时,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize 值,那么这个线程会被销毁。 + > 根据上面三个参数配置,线程池会对任务进行如下处理方式 + ``` + 当提交一个新的任务到线程池,线程池会根据当前线程池中正在进行的线程数量来决定该任务的处理方式,处理方式共有三种:直接切换、使用无限队列、使用有界队列 + 1. 直接切换常用的队列就是SynchronousQueue + 2. 使用无限队列就是使用基于链表的队列,比如:LinkedBlockingQueue,如果使用这种方式,线程池中创建的最大线程就是corePoolSize,此时maximumPoolSize不会起作用,因为队列是无限的,workQueue不会满。当线程池中的所有的核心线程都是运行状态时,提交新任务,就会放入等待队列中 + 3. 使用有界队列比如ArrayBlockingQueue,使用这种方式可以将线程池的最大线程数限制为maximumPoolSize,可以降低资源的消耗。 + ``` +> 参数 +* keepAliveTime: 线程没有任务执行时最多保持多久时间终止 +* unit: keepAliveTime的时间单位 +* threadFactory: 线程工厂,用来创建线程 +* rejectHandler: 拒绝处理任务时的策略 + ``` + 如果workQueue阻塞队列满了,并且没有空闲的线程池,此时,继续提交任务,需要采取一种策略来处理这个任务 + 1. 默认直接抛出异常,实现类为AbortPolicy + 2. 用调用者所在的线程来执行任务,实现类为CallerRunsPolicy + 3. 丢弃队列中最靠前的任务,并执行当前任务,实现类DiscardOldestPolicy + 4. 直接丢弃当前任务,实现类为DiscardPolicy + ``` +> ThreadPoolExecutor提供的启动和停止任务的方法 +1. execute(); 提交任务,交给线程池执行 +2. submit(); 提交任务,能够返回执行结果execute + Future +3. shutdown(); 关闭线程池,等待任务都执行完 +4. shutdownNow(); 立即关闭线程池,不等待任务执行完 + +#### 线程池 +> 配置 +1. CPU密集型,设置为N + 1 +2. IO密集型,设置为2N +> 创建 +* 使用Executors工具类创建线程池 +* 使用ThreadPoolExecutor类创建线程池 +* 使用ScheduledThreadPoolExecutor类创建线程池 + +### 建议 +1. SimpleDateFormat类是线程不安全的,推荐使用JDK8中的DateTimeFormatter,高并发场景中推荐使用joda-time库来处理日格式化,效率高 +`protected Calendar calendar;`多个线程之间共享变量calendar,并修改calendar。因此在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。 + # 引用 * https://www.cnblogs.com/skywang12345/ * https://www.cnblogs.com/walixiansheng/p/9588603.html diff --git "a/java/jvm/JVM\350\231\232\346\213\237\346\234\272\347\233\221\346\216\247\345\217\212\346\200\247\350\203\275\350\260\203\344\274\230.md" "b/java/jvm/JVM\350\231\232\346\213\237\346\234\272\347\233\221\346\216\247\345\217\212\346\200\247\350\203\275\350\260\203\344\274\230.md" index bb458435..99e11eb8 100644 --- "a/java/jvm/JVM\350\231\232\346\213\237\346\234\272\347\233\221\346\216\247\345\217\212\346\200\247\350\203\275\350\260\203\344\274\230.md" +++ "b/java/jvm/JVM\350\231\232\346\213\237\346\234\272\347\233\221\346\216\247\345\217\212\346\200\247\350\203\275\350\260\203\344\274\230.md" @@ -100,7 +100,28 @@ java.rmi.ConnectException: Connection refused to host: y.y.y.y; nested exception is: ``` > 注意:我在这里查看了远程机器的hosts,发现其配有一些其他的IP,将其删除后能够联通 -* +* 快速定位导致cpu飙升的线程堆栈信息 + ```log + top 首先通过top命令找到高负载的CPU,获取进程id + top -p <进程id> 精确定位到cpu高的进程,然后按H键,查看该进程所有线程 + 或者 top -p 进程id -H 查看进程下的线程 + printf "%x" 进程id 将进程号转化为16进制,注意把十六进制的大写字母转换为小写 + jstack 进程id > xxx.txt 导出日志,然后在日志中查找nid=转换后进程id + 或者 jstack 进程ID|grep -A 10 55a0 10表示这个线程所在行后面10行,55a0是进程ID转换后的十六进制 + ``` +* 查看堆内存使用情况 + ``` + jps查看各个应用进程id + jmap -heap java项目进程id + jmap -histo 进程id > log.txt 查看此应用中各实例生成情况 + jmap -histo:live [pid] > log.txt 过滤存活的对象 + ``` +* 查找代码死锁 + ``` + jstack 进程id > xxx.txt 导出日志 + 搜索 deadlock 或者查 locked关键字找到发生死锁线程 + ``` + # 引用 * [jvisualvm简要说明](https://blog.csdn.net/weixin_38750084/article/details/83314046) * [jvisualvm 连接 jstatd 远程监控 jvm 或 Visual GC提示"不受此JVM支持“](https://blog.csdn.net/liupeifeng3514/article/details/78998161) diff --git "a/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243Java\350\231\232\346\213\237\346\234\272.md" "b/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243Java\350\231\232\346\213\237\346\234\272.md" index 658e300a..a4ed3568 100755 --- "a/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243Java\350\231\232\346\213\237\346\234\272.md" +++ "b/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243Java\350\231\232\346\213\237\346\234\272.md" @@ -68,6 +68,9 @@ Java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用 * App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。 * 除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内,但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。 +### 堆内内存与堆外内存 +堆内拷贝到堆外的原因: 操作系统把内存中的数据写入磁盘或网络时,要求数据所在的内存区域不能变动,但是JVM的GC机制会对内存进行整理,导致数据内存地址发生变化,所以无奈,JDK只能先拷贝到堆外内存(不受GC影响),然后把这个地址发给操作系统。 + # *JDK* ### JDK中自带的工具 #### `version 1.8` diff --git a/java/spring/image/documented-annotation.png b/java/spring/image/documented-annotation.png new file mode 100644 index 00000000..1f7ce212 Binary files /dev/null and b/java/spring/image/documented-annotation.png differ diff --git a/java/spring/image/hystrix.png b/java/spring/image/hystrix.png new file mode 100644 index 00000000..b61c63f3 Binary files /dev/null and b/java/spring/image/hystrix.png differ diff --git a/java/spring/spring-annotation.md b/java/spring/spring-annotation.md new file mode 100644 index 00000000..6c67f9a2 --- /dev/null +++ b/java/spring/spring-annotation.md @@ -0,0 +1,395 @@ +### 相关问题 +* 为什么要引入注解 +* 元注解有哪些 +* Spring常用的注解有哪些 +* SpringBoot常用注解有哪些 +* SpringCloud常用注解有哪些 + +#### 为什么要引入注解 +注解是JDK1.5引入的功能。注解可以看作是对类和方法的扩展标识,这些标识可以在编译,类加载,运行时被读取,并执行相应的处理。在注解之前,我们只能通过xml配置的方式来做。由于XML的配置诸多不便,并且配置和代码分离,不便于代码阅读,慢慢的注解就替代了xml配置的方式。 + +#### 元注解有哪些 + +元注解是负责对其它注解进行说明的注解,自定义注解时可以使用元注解。Java 5 定义了 4 个注解,分别是 @Documented、@Target、@Retention 和 @Inherited。Java 8 又增加了 @Repeatable 和 @Native 两个注解 +* `@Documented` + +@Documented 是一个标记注解,没有成员变量。用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。默认情况下,JavaDoc 是不包括注解的,但如果声明注解时指定了 @Documented,就会被 JavaDoc 之类的工具处理,所以注解类型信息就会被包括在生成的帮助文档中。使用`javadoc -d doc MyAnnotation.java XXXX.java`就生成了javadoc了 +```java +@Documented +@Target({ ElementType.TYPE, ElementType.METHOD }) +public @interface MyDocumented { + public String value() default "这是@Documented注解"; +} +// Target为什么要加个ElementType.TYPE,是因为生成javadoc的时候你得知道是哪个类啊 +@MyDocumented +public class DocumentedTest { + /** + * 测试document + */ + @MyDocumented + public String Test() { + return "C语言中文网Java教程"; + } +} + +javac MyDocumented.java DocumentedTest.java +javadoc -d doc MyDocumented.java DocumentedTest.java +``` +![](image/documented-annotation.png) + +* `@Target` + +@Target 注解用来指定一个注解的使用范围,即被 @Target 修饰的注解可以用在什么地方。@Target 注解有一个成员变量(value)用来设置适用目标,value 是 java.lang.annotation.ElementType 枚举类型的数组,下表为 ElementType 常用的枚举常量: +``` +PACKAGE 用于包 +TYPE 用于类、接口(包括注解类型)或enum声明 +CONSTRUCTOR 用于构造方法 +METHOD 用于方法 +FIELD 用于成员变量(包括枚举常量) +LOCAL_VARIABLE 用于局部变量 +PARAMETER 用于类型参数(JDK1.8新增) +``` + +* `@Retention` + +@Retention用于描述注解的生命周期,也就是该注解被保留的时间长短。@Rentention注解中的成员变量value用来设置保留策略,value是java.lang.annotation.RententionPolicy枚举类型,RententionPolicy有3个枚举常量: +``` +SOURCE 在源文件中有效,当Java文件编译成class文件的时候,注解被遗弃 +CLASS 在class文件中有效, 但jvm加载class文件时被遗弃,这是默认的生命周期 +RUNTIME 在运行时有效,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在 +这3个生命周期分别对应于:Java源文件 -> .class文件 -> 内存中的字节码 +``` + +* `@Inherited` + +@Inherited是一个标记注解,用来指定该注解可以被继承。使用@Inherited注解的Class类,表示这个注解可以被用于该Class类的子类。 + +* `@Repeatable` + +@Repeatable注解是Java8新增的,解决了在方法,变量或者类上重复使用注解的问题 +```java +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Values { + Value[] value(); +} + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(Values.class) +public @interface Value { + String value() default "value"; +} + +public class AnnotationClass { + + @Value("hello") // 这里通过反射获取方法的注解class是Values,而不是Value + @Value("world") + public void test(String var1, String var2) { + System.out.println(var1 + " " + var2); + } +} +``` + +* `@Native` + +使用@Native注解修饰的成员变量,便是可以被本地代码引用 + +#### Spring常用的注解有哪些 + +* 声明bean的注解 + * @Component 组件,没有明确的角色。作用及范围:把对象加载到spring容器中,最基础的存在,很多的注解都是继承它的,只有一个属性值,默认值是“ + * @Controller 在展示层使用,控制器的声明。作用及范围:作用在控制器上的注解,与Service一样,业务领域区分。可以返回string跳转jsp,ftl,html等模板页面,也可以返回实体对象 + * @RestController 在展示层使用,返回的是JSON格式的数据。等同于@Controller + @ResponseBody + * @Service 在业务逻辑层使用。作用及范围:一般用于service层的注解,继承了Component组件,本质上一样,方便做业务范围区分而已。 + * @Repository 在数据访问层使用。作用及范围:作用于dao层的注解,很多经常用JPA的同学都清楚这个东西,与Service本质上一样,业务领域上区别而已 + ``` + @Repository(value="userDao")注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。当Service需要使用Spring创建的名字叫“userDao”的UserDaoImpl实例时,就可以使用@Resource(name = "userDao")注解告诉Spring,Spring把创建好的userDao注入给Service即可。 + ``` +* 注入bean的注解 + * @Autowired 作用及范围:它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,其实就是获取容器中的对象。通过@Autowired的使用来消除set,get方法。 + ``` + 注意事项: + 在使用@Autowired时,首先在容器中查询对应类型的bean + 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据 + 如果查询的结果不止一个,那么@Autowired会根据名称来查找。 + 如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false + ``` + * @Resource 由JSR-250提供,根据名称进行自动装配的,一般会指定一个name属性,可以作用在变量、setter方法上。 + * @Inject 由JSR-330提供需要导入javax.inject.Inject;实现注入,根据类型byType进行自动装配的,如果需要按名称进行装配,则需要配合@Named,可以作用在变量、setter方法、构造函数上。很少用。 +* java配置类相关注解 + * @Configuration 声明当前类为配置类,相当于xml形式的Spring配置。用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法 + * @Bean 注解在方法上,声明当前方法的返回值为一个bean, 替代xml的方式。@Bean:Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。SpringIOC 容器管理一个或者多个bean,这些bean都需要在@Configuration注解下进行创建,在一个方法上使用@Bean注解就表明这个方法需要交给Spring进行管理。 + ``` + @Configuration + public class AppConfig { + // 未指定bean 的名称,默认采用的是 "方法名" + "首字母小写"的配置方式 + @Bean + public MyBean myBean(){ + return new MyBean(); + } + } + + public class MyBean { + + public MyBean(){ + System.out.println("MyBean Initializing"); + } + } + ``` + * @Scope注解设置Spring容器如何新建Bean实例 + * Singleton 默认模式,单例,一个Spring容器中只有一个bean实例 + * Protetype 每次调用新建一个bean + * Request(web项目中,给每个http request新建一个bean) + * Session(web项目中,给每个http session新建一个bean) + * GlobalSession(给每个global http session新建一个bean实例) + * @PostConstruct由JSR-250提供,在构造函数执行完之后执行,等价于xml中bean配置的的initMethod + * @PreDestory由JSR-250提供,在Bean销毁之前执行,等价于xml中bean配置的destroyMethod + * @ComponentScan用于对Component进行扫描,替代xml的方式。作用及范围:扫描当前类下面的所有对象,为什么说Component是最基础的东西,就是要给这个注解扫描,非常巧妙的设计,可以扫描多个包。 + * @WishlyConfiguration为@Configuration与@ComponentScan的组合注解,用的很少 +* 切面(AOP)相关注解 + * @Aspect声明一个切面(类上),使用@After,@Before,@Around定义建言(advice),可直接将拦截规则(切点)作为参数。在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上) + * @After在方法执行之后执行(方法上) + * @Before在方法执行前执行(方法上) + * @Around在方法执行之前与之后执行(方法上) + * @PointCut声明切点 +* 环境切换 + * @Profile通过设定Environment的ActiveProfiles来设定当前context需要使用的配置环境(类或者方法上) + ```java + @PropertySource("classpath:/user.properties") + @Configuration + public class MainConfigOfProfile implements EmbeddedValueResolverAware{ + + @Profile("test") + @Bean("testUser") + public User testUser() { + User a =new User(); + return a; + } + + @Profile("dev") + @Bean("devUser") + public User devUser() { + User a =new User(); + return a; + } + } + ``` + * @Conditional使用此注解定义激活bean的条件,通过实现Condition接口,并重写matches方法,从而决定该bean是否被实例化(方法上) + ```java + @Configuration + public class BeanConfig { + + //只有一个类时,大括号可以省略 + //如果WindowsCondition的实现方法返回true,则注入这个bean + @Conditional({WindowsCondition.class}) + @Bean(name = "bill") + public Window window(){ + return new Window(); + } + + //如果LinuxCondition的实现方法返回true,则注入这个bean + @Conditional({LinuxCondition.class}) + @Bean("linux") + public Linex linux(){ + return new Linex(); + } + } + ``` +* 配置注解 + * @Value注解 + ```java + @Value("normal") + private String normal; // 注入普通字符串 + + @Value("#{systemProperties['os.name']}") + private String systemPropertiesName; // 注入操作系统属性 + + @Value("#{ T(java.lang.Math).random() * 100.0 }") + private double randomNumber; //注入表达式结果 + + @Value("#{beanInject.another}") + private String fromAnotherBean; // 注入其他Bean属性:注入beanInject对象的属性another,类具体定义见下面 + + @Value("classpath:com/hry/spring/configinject/config.txt") + private Resource resourceFile; // 注入文件资源 + + @Value("http://www.baidu.com") + private Resource testUrl; // 注入URL资源 + ``` + * @PropertySource加载配置文件(类上) + ```java + @PropertySource(value = {"classpath:test.properties"}) + @Component + @ConfigurationProperties(prefix = "test") + public class Test { + private Integer id; + private String lastName; + } + ``` + +* 异步相关 + * @EnableAsync 配置在类上,开启对异步任务的支持 + * @Async在实际执行的bean方法使用该注解来申明其是一个异步任务(方法上或类上的所有方法都将异步,需要@EnableAsync开启异步任务) +* 定时任务 + * @EnableScheduling 配置在类上,开启计划任务的支持 + * @Scheduled声明这是一个任务,包括cron, fixDelay, fixRate等类型,用于方法上,需要先开启计划任务的支持 +* Enable*注解 + * @EnableAspectJAutoProxy开启对AspectJ自动代理的支持 + * @EnableAsync开启异步方法的支持 + * @EnableScheduling开启计划任务的支持 + * @EnableWebMvc开启Web MVC的配置支持 + * @EnableConfigurationProperties开启对@ConfigurationProperties注解配置Bean的支持 + * @EnableJpaRepositories开启对SpringData JPA Repository的支持 + * @EnableTransactionmanagement开启注解式事务的支持 + * @EnableCaching开启注解式的缓存支持 +* 持久层注解 + * @TableField(value="数据表字段", exist=true/false) 表示该属性为数据库表字段 + * @TableName:数据库表相关 + * @TableId:表主键标识 + * @JsonIgnore:作用是json序列化时将Java bean中的一些属性忽略掉,序列化和反序列化都受影响 + * @JsonProperty用于将参数中的字段转换为DTO的字段 + * @Transactional:声明式事务注解,注解在方法上 + ``` + Spring框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出个RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将 不 被标识进行事务回滚。 + 1 让checked例外也回滚:在整个方法前加上@Transactional(rollbackFor=Exception.class) + 2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class) + 3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED) + 注意: 如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。 + ``` +* 其他注解 + * @CrossOrigin用于class和method上用来支持跨域请求 + * @ExceptionHandler用于方法级别,声明对Exception的处理逻辑 + * @ControllerAdvice全局异常处理,全局数据绑定,全局数据预处理 + ```java + @ControllerAdvice + public class MyGlobalExceptionHandler { + @ExceptionHandler(Exception.class) + public ModelAndView customException(Exception e) { + ModelAndView mv = new ModelAndView(); + mv.addObject("message", e.getMessage()); + mv.setViewName("error"); + return mv; + } + } + + @ControllerAdvice + public class MyGlobalExceptionHandler { + @ModelAttribute(name = "md") + public Map mydata() { + HashMap map = new HashMap<>(); + map.put("gender", "女"); + return map; + } + } + ``` + +#### 常用注解有哪些 + +* Hibernate Validator 参考文章 https://zhuanlan.zhihu.com/p/194097505 +``` +在程序开发中,经常要对数据进行校验后再进行业务处理。如果在业务代码中进行Bean的字段校验,会使得代码变的非常繁琐。JSR303 - Bean Validation[JSR Java Specification Requests]为JavaBean的验证定义了相关的元数据模型和API。 +This JSR will define a meata-data model and API for JavaBeanTM validation, with overrides and extended meta-data through the use of XML validateion descriptors. 在Java8之后,又推出JSR380 - Bean Validation 2.0。 +JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。 +Hibernate Validator是Bean Validation的实现,Hibernate Validator内置了JSR303/JSR380中的所有的constraint[约束,限制]的实现,还额外定义了很多自定义的constraint。 +``` +* 导入依赖 spring-boot-starter-web中集成了Hibernate Validator工具,无需额外引用。 +* maven依赖 hibernate-validator +* Bean Validation中内置的constraint +``` +@Null 元素必须为null +@NotNull 元素不能为null +@NotBlank 元素不能为null且不能为空,用于string +@NotEmpty 元素不能为null且不能为空集合 +@Length 元素字符串长度必须在指定的范围内 @Length(min=1, max = 20, message = "xxx") +@Negative 元素必须是负数 +@NegativeOrZero 元素必须是负数或者0 +@Positive 元素必须是正数 +@PositiveOrZero 元素必须是正数或者0 +@Size 元素集合大小在指定范围@Size(min = 1, max = 5, message = "")。支持字符串数组,Collection, Map, Array +@Min 元素最小整数值, value是long类型,可用于int long +@Max 元素最大整数值, value是long类型,可用于int long +@DecimalMin 元素是decimal类型,最小值 +@DecimalMax 元素是decimal类型,最大值 +@Digits 元素必须为一个指定格式的数字 @Digits(integer=, fraction=) integer指定整数精度,fraction指定小数精度。可用于Double, Intger, Decimal + @Digits(integer=10, fraction=0) + private Double double1 = 0.0; +@AssertFalse 元素必须为false +@AssertTrue 元素必须为true,可用于用户同意条款 +@Email 元素必须是电子邮箱地址 @Email(regexp = "^[^@\s]+@[^@\s]+\.[^@\s]+$") 使用的是微软官方给出的电子邮箱校验正则表达式 +@Pattern 元素必须符合正则表达式 +@Past 元素必须是过去的日期 获取的是服务器时间 SystemClock(ZoneId.systemDefault()) < +@PastOrPresent 元素必须是过去的日期或者现在 <= +@Future 元素必须是将来的日期 +@FutureOrPresent 元素必须是将来日期或者现在 +@Range 元素必须在合适的范围内 @Range(min=, max, message) +@SafeHtml 判断字符串是否是安全的html Validate a rich text value provided by the user to ensure that it contains no malicious code, such as embedded