# Maven
## åºæ¬ä»ç»
### Mvnä»ç»
Mavenï¼æ¬è´¨æ¯ä¸ä¸ªé¡¹ç®ç®¡çå·¥å
·ï¼å°é¡¹ç®å¼åå管çè¿ç¨æ½è±¡æä¸ä¸ªé¡¹ç®å¯¹è±¡æ¨¡åï¼POMï¼
POMï¼Project Object Model 项ç®å¯¹è±¡æ¨¡åãMaven æ¯ç¨ Java è¯è¨ç¼åçï¼ç®¡ççä¸è¥¿ä»¥é¢å对象çå½¢å¼è¿è¡è®¾è®¡ï¼æç»æä¸ä¸ªé¡¹ç®çæä¸ä¸ªå¯¹è±¡ï¼è¿ä¸ªå¯¹è±¡å«å POM
pom.xmlï¼Maven éè¦ä¸ä¸ª pom.xml æä»¶ï¼Maven éè¿å è½½è¿ä¸ªé
ç½®æä»¶å¯ä»¥ç¥é项ç®çç¸å
³ä¿¡æ¯ï¼è¿ä¸ªæä»¶ä»£è¡¨å°±ä¸ä¸ªé¡¹ç®ã妿å 8 个项ç®ï¼å¯¹åºçæ¯ 8 个 pom.xml æä»¶
ä¾èµç®¡çï¼Maven å¯¹é¡¹ç®ææä¾èµèµæºçä¸ç§ç®¡çï¼å®å项ç®ä¹é´æ¯ä¸ç§ååå
³ç³»ï¼å³åé¡¹ç®æ¶å¯ä»¥ç®¡çæéè¦çå
¶ä»èµæºï¼å½å
¶ä»é¡¹ç®éè¦ä¾èµæä»¬é¡¹ç®æ¶ï¼Maven ä¹ä¼ææä»¬ç项ç®å½ä½ä¸ç§èµæºå»è¿è¡ç®¡çã
管çèµæºçåå¨ä½ç½®ï¼æ¬å°ä»åºï¼ç§æï¼ä¸å¤®ä»åº

åºæ¬ä½ç¨ï¼
* é¡¹ç®æå»ºï¼æä¾æ åçï¼è·¨å¹³å°çèªå¨åæå»ºé¡¹ç®çæ¹å¼
* ä¾èµç®¡çï¼æ¹ä¾¿å¿«æ·ç管ç项ç®ä¾èµçèµæºï¼jar å
ï¼ï¼é¿å
èµæºé´ççæ¬å²çªçé®é¢
* ç»ä¸å¼åç»æï¼æä¾æ åçï¼ç»ä¸ç项ç®å¼åç»æ

åç®å½åæ¾èµæºç±»å说æï¼
* src/main/javaï¼é¡¹ç® java æºç
* src/main/resourcesï¼é¡¹ç®çç¸å
³é
ç½®æä»¶ï¼æ¯å¦ mybatis é
ç½®ï¼xml æ å°é
ç½®ï¼èªå®ä¹é
ç½®æä»¶çï¼
* src/main/webappï¼web èµæºï¼æ¯å¦ htmlãcssãjs çï¼
* src/test/javaï¼æµè¯ä»£ç
* src/test/resourcesï¼æµè¯ç¸å
³é
ç½®æä»¶
* src/pom.xmlï¼é¡¹ç® pom æä»¶
åèè§é¢ï¼https://www.bilibili.com/video/BV1Ah411S7ZE
***
### åºç¡æ¦å¿µ
ä»åºï¼ç¨äºåå¨èµæºï¼ä¸»è¦æ¯åç§ jar å
ãææ¬å°ä»åºï¼ç§æï¼ä¸å¤®ä»åºï¼ç§æåä¸å¤®ä»åºé½æ¯è¿ç¨ä»åº
* ä¸å¤®ä»åºï¼Maven å¢éèªèº«ç»´æ¤çä»åºï¼å±äºå¼æºç
* ç§æï¼åå
¬å¸/é¨é¨çå°èå´å
åå¨èµæºçä»åºï¼ç§æä¹å¯ä»¥ä»ä¸å¤®ä»åºè·åèµæºï¼ä½ç¨ï¼
* ä¿åå
·æçæçèµæºï¼å
å«è´ä¹°æèªä¸»ç åç jar
* ä¸å®èå´å
å
±äº«èµæºï¼è½åå°ä»
对å
ä¸å¯¹å¤å¼æ¾
* æ¬å°ä»åºï¼å¼åè
èªå·±çµèä¸åå¨èµæºçä»åºï¼ä¹å¯ä»è¿ç¨ä»åºè·åèµæº
åæ ï¼Maven ä¸çåæ ç¨äºæè¿°ä»åºä¸èµæºçä½ç½®
* ä½ç¨ï¼ä½¿ç¨å¯ä¸æ è¯ï¼å¯ä¸æ§å®ä¹èµæºä½ç½®ï¼éè¿è¯¥æ è¯å¯ä»¥å°èµæºçè¯å«ä¸ä¸è½½å·¥ä½äº¤ç±æºå¨å®æ
* https://mvnrepository.comï¼æ¥è¯¢ maven æä¸ä¸ªèµæºçåæ ï¼è¾å
¥èµæºåç§°è¿è¡æ£ç´¢
* ä¾èµè®¾ç½®ï¼
* groupIdï¼å®ä¹å½åèµæºé¶å±ç»ç»åç§°ï¼é常æ¯ååååï¼å¦ï¼org.mybatisï¼
* artifactIdï¼å®ä¹å½åèµæºçåç§°ï¼é常æ¯é¡¹ç®ææ¨¡ååç§°ï¼å¦ï¼crmãsmsï¼
* versionï¼å®ä¹å½åèµæºççæ¬å·
* packagingï¼å®ä¹èµæºçæå
æ¹å¼ï¼åå¼ä¸è¬æå¦ä¸ä¸ç§
* jarï¼è¯¥èµæºææ jar å
ï¼é»è®¤æ¯ jar
* warï¼è¯¥èµæºææ war å
* pomï¼è¯¥èµæºæ¯ä¸ä¸ªç¶èµæºï¼è¡¨æä½¿ç¨ Maven 忍¡å管çï¼ï¼æå
æ¶åªçæä¸ä¸ª pom.xml ä¸çæ jar æå
¶ä»å
ç»æ
***
## ç¯å¢æå»º
### ç¯å¢é
ç½®
Maven çå®ç½ï¼http://maven.apache.org/
ä¸è½½å®è£
ï¼Maven æ¯ä¸ä¸ªç»¿è²è½¯ä»¶ï¼è§£åå³å®è£
ç®å½ç»æï¼
* binï¼å¯æ§è¡ç¨åºç®å½
* bootï¼Maven èªèº«çå¯å¨å è½½å¨
* confï¼Maven é
ç½®æä»¶çåæ¾ç®å½
* libï¼Mavenè¿è¡æéåºçåæ¾ç®å½
é
ç½® MAVEN_HOMEï¼

Path ä¸é
ç½®ï¼`%MAVEN_HOME%\bin`
ç¯å¢åéé
置好ä¹åéè¦æµè¯ç¯å¢é
ç½®ç»æï¼å¨ DOS å½ä»¤çªå£ä¸è¾å
¥ä»¥ä¸å½ä»¤æ¥çè¾åºï¼`mvn -v`
***
### ä»åºé
ç½®
é»è®¤æ
åµ Maven æ¬å°ä»åºå¨ç³»ç»ç¨æ·ç®å½ä¸ç `.m2/repository`ï¼ä¿®æ¹ Maven çé
ç½®æä»¶ `conf/settings.xml` æ¥ä¿®æ¹ä»åºä½ç½®
* ä¿®æ¹æ¬å°ä»åºä½ç½®ï¼æ¾å° æ ç¾ï¼ä¿®æ¹é»è®¤å¼
```xml
E:\Workspace\Java\Project\.m2\repository
```
注æï¼å¨ä»åºçå级ç®å½å³ `.m2` ä¹åºè¯¥å
å«ä¸ä¸ª `settings.xml` é
ç½®æä»¶ï¼å±é¨ç¨æ·é
ç½®ä¼å
ä¸å
¨å±é
ç½®
* å
¨å± setting å®ä¹äº Maven çå
Œ
±é
ç½®
* ç¨æ· setting å®ä¹äºå½åç¨æ·çé
ç½®
* ä¿®æ¹è¿ç¨ä»åºï¼å¨é
ç½®æä»¶ä¸æ¾å° `` æ ç¾ï¼å¨è¿ç»æ ç¾ä¸æ·»å å½å
éå
```xml
nexus-aliyun
central
Nexus aliyun
http://maven.aliyun.com/nexus/content/groups/public
```
* ä¿®æ¹é»è®¤ JDKï¼å¨é
ç½®æä»¶ä¸æ¾å° `` æ ç¾ï¼æ·»å é
ç½®
```xml
jdk-10
true
10
UTF-8
10
10
```
***
## é¡¹ç®æå»º
### æå¨æå»º
1. å¨ E çä¸å建ç®å½ mvnproject è¿å
¥è¯¥ç®å½ï¼ä½ä¸ºæä»¬çæä½ç®å½
2. å建æä»¬ç Maven 项ç®ï¼å建ä¸ä¸ªç®å½ `project-java` ä½ä¸ºæä»¬çé¡¹ç®æä»¶å¤¹ï¼å¹¶è¿å
¥å°è¯¥ç®å½
3. å建 Java 代ç ï¼æºä»£ç ï¼æå¨ç®å½ï¼å³å建 `src/main/java`
4. å建é
ç½®æä»¶æå¨ç®å½ï¼å³å建 `src/main/resources`
5. å建æµè¯æºä»£ç æå¨ç®å½ï¼å³å建 `src/test/java`
6. å建æµè¯åæ¾é
ç½®æä»¶åæ¾ç®å½ï¼å³ `src/test/resources`
7. å¨ `src/main/java` ä¸å建ä¸ä¸ªå
ï¼æ³¨æå¨ Windos æä»¶å¤¹ä¸å°±æ¯å建ç®å½ï¼`demo`ï¼å¨è¯¥ç®å½ä¸å建 `Demo.java` æä»¶ï¼ä½ä¸ºæ¼ç¤ºæé Java ç¨åºï¼å
容å¦ä¸
```java
package demo;
public class Demo{
public String say(String name){
System.out.println("hello "+name);
return "hello "+name;
}
}
```
8. å¨ `src/test/java` ä¸å建ä¸ä¸ªæµè¯å
ï¼ç®å½ï¼`demo`ï¼å¨è¯¥å
ä¸å建æµè¯ç¨åº `DemoTest.java`
```java
package demo;
import org.junit.*;
public class DemoTest{
@Test
public void testSay(){
Demo d = new Demo();
String ret = d.say("maven");
Assert.assertEquals("hello maven",ret);
}
}
```
9. **å¨ `project-java/src` ä¸å建 `pom.xml` æä»¶ï¼æ ¼å¼å¦ä¸ï¼**
```xml
4.0.0
jar
demo
project-java
1.0
junit
junit
4.12
```
10. æå»ºå®æ Maven ç项ç®ç»æï¼éè¿ Maven æ¥æå»ºé¡¹ç®ãMaven çæå»ºå½ä»¤ä»¥ `mvn` å¼å¤´ï¼å颿·»å åè½åæ°ï¼å¯ä»¥ä¸æ¬¡æ§æ§è¡å¤ä¸ªå½ä»¤ï¼ç¨ç©ºæ ¼å离
* `mvn compile`ï¼ç¼è¯
* `mvn clean`ï¼æ¸
ç
* `mvn test`ï¼æµè¯
* `mvn package`ï¼æå
* `mvn install`ï¼å®è£
å°æ¬å°ä»åº
注æï¼æ§è¡æä¸æ¡å½ä»¤ï¼å伿å颿æç齿§è¡ä¸é
***
### IDEAæå»º
#### ä¸ç¨åå
1. å¨ IDEA ä¸é
ç½® Mavenï¼éæ© maven3.6.1 鲿¢ä¾èµé®é¢
2. å建 Mavenï¼New Module â Maven â ä¸éä¸ Create from archetype
3. å¡«å项ç®çåæ
* GroupIdï¼demo
* ArtifactIdï¼project-java
4. æ¥çåç®å½é¢è²æ è®°æ¯å¦æ£ç¡®

5. IDEA å³ä¾§ä¾§æ æ Maven Projectï¼æå¼åæ Lifecycle çå½å¨æ

6. èªå®ä¹ Maven å½ä»¤ï¼Run â Edit Configurations â å·¦ä¸è§ + â Maven

***
#### 使ç¨åå
æ®éå·¥ç¨ï¼
1. å建 Maven 项ç®çæ¶åéæ©ä½¿ç¨åå骨æ¶

2. åå»ºå®æååç°éè¿è¿ç§æ¹å¼ç¼ºå°ä¸äºç®å½ï¼éè¦æå¨å»è¡¥å
¨ç®å½ï¼å¹¶ä¸è¦å¯¹è¡¥å
¨çç®å½è¿è¡æ è®°
Web å·¥ç¨ï¼
1. éæ© Web 对åºçåå骨æ¶ï¼éæ© Maven å¼å¤´çæ¯ç®åçï¼

2. éè¿ååå建 Web 项ç®å¾å°çç®å½ç»ææ¯ä¸å
¨çï¼å æ¤éè¦æä»¬èªè¡è¡¥å
¨ï¼åæ¶è¦æ è®°æ£ç¡®
3. Web å·¥ç¨å建ä¹åéè¦å¯å¨è¿è¡ï¼ä½¿ç¨ tomcat æä»¶æ¥è¿è¡é¡¹ç®ï¼å¨ `pom.xml` 䏿·»å æä»¶çåæ ï¼
```xml
4.0.0
war
web01
demo
web01
1.0-SNAPSHOT
org.apache.tomcat.maven
tomcat7-maven-plugin
2.1
80
/
```
4. æä»¶é
置以åï¼å¨ IDEA å³ä¾§ `maven-project` æä½é¢æ¿çå°è¯¥æä»¶ï¼å¹¶ä¸å¯ä»¥å©ç¨è¯¥æä»¶å¯å¨é¡¹ç®ï¼web01 â Plugins â tomcat7 â tomcat7:run
***
## ä¾èµç®¡ç
### ä¾èµé
ç½®
ä¾èµæ¯æå¨å½å项ç®ä¸è¿è¡æéç jarï¼ä¾èµé
ç½®çæ ¼å¼å¦ä¸ï¼
```xml
junit
junit
4.12
```
***
### ä¾èµä¼ é
ä¾èµå
·æä¼ éæ§ï¼å两ç§ï¼
* ç´æ¥ä¾èµï¼å¨å½å项ç®ä¸éè¿ä¾èµé
置建ç«çä¾èµå
³ç³»
* é´æ¥ä¾èµï¼è¢«ä¾èµçèµæºå¦æä¾èµå
¶ä»èµæºï¼å表æå½å项ç®é´æ¥ä¾èµå
¶ä»èµæº
注æï¼ç´æ¥ä¾èµåé´æ¥ä¾èµå
¶å®ä¹æ¯ä¸ä¸ªç¸å¯¹å
³ç³»
ä¾èµä¼ éçå²çªé®é¢ï¼å¨ä¾èµä¼ éè¿ç¨ä¸äº§çäºå²çªï¼æä¸ç§ä¼å
æ³å
* è·¯å¾ä¼å
ï¼å½ä¾èµä¸åºç°ç¸åèµæºæ¶ï¼å±çº§è¶æ·±ï¼ä¼å
级è¶ä½ï¼åä¹åè¶é«
* 声æä¼å
ï¼å½èµæºå¨ç¸åå±çº§è¢«ä¾èµæ¶ï¼é
置顺åºé åçè¦çé åç
* ç¹æ®ä¼å
ï¼å½å级é
ç½®äºç¸åèµæºçä¸åçæ¬æ¶ï¼åé
ç½®çè¦çå
é
ç½®ç
**å¯éä¾èµ**ï¼å¯¹å¤éèå½åæä¾èµçèµæºï¼ä¸éæ
```xml
junit
junit
4.11
true
```
**æé¤ä¾èµ**ï¼ä¸»å¨æå¼ä¾èµçèµæºï¼è¢«æé¤çèµæºæ éæå®çæ¬
```xml
junit
junit
4.12
org.hamcrest
hamcrest-core
```
***
### ä¾èµèå´
ä¾èµç jar é»è®¤æ
åµå¯ä»¥å¨ä»»ä½å°æ¹å¯ç¨ï¼å¯ä»¥éè¿ `scope` æ ç¾è®¾å®å
¶ä½ç¨èå´ï¼æä¸ç§ï¼
* 主ç¨åºèå´ææï¼src/main ç®å½èå´å
ï¼
* æµè¯ç¨åºèå´å
ææï¼src/test ç®å½èå´å
ï¼
* æ¯å¦å䏿å
ï¼package æä»¤èå´å
ï¼
`scope` æ ç¾çå弿åç§ï¼`compile,test,provided,runtime`

**ä¾èµèå´çä¼ éæ§ï¼**

***
## çå½å¨æ
### ç¸å
³äºä»¶
Maven çæå»ºçå½å¨ææè¿°çæ¯ä¸æ¬¡æå»ºè¿ç¨ç»åäºå¤å°ä¸ªäºä»¶
æå¸¸ç¨çä¸å¥æµç¨ï¼compile â test-compile â test â package â install
* cleanï¼æ¸
çå·¥ä½
* pre-cleanï¼æ§è¡ä¸äºå¨ clean ä¹åçå·¥ä½
* cleanï¼ç§»é¤ä¸ä¸æ¬¡æå»ºäº§ççæææä»¶
* post-cleanï¼æ§è¡ä¸äºå¨ clean ä¹åç«å»å®æçå·¥ä½
* defaultï¼æ ¸å¿å·¥ä½ï¼ä¾å¦ç¼è¯ï¼æµè¯ï¼æå
ï¼é¨ç½²çï¼æ¯ä¸ªäºä»¶å¨æ§è¡ä¹åé½ä¼**å°ä¹åçææäºä»¶ä¾æ¬¡æ§è¡ä¸é**

* siteï¼äº§çæ¥åï¼åå¸ç«ç¹ç
* pre-siteï¼æ§è¡ä¸äºå¨çæç«ç¹ææ¡£ä¹åçå·¥ä½
* siteï¼çæé¡¹ç®çç«ç¹ææ¡£
* post-siteï¼æ§è¡ä¸äºå¨çæç«ç¹ææ¡£ä¹å宿çå·¥ä½ï¼å¹¶ä¸ºé¨ç½²ååå¤
* site-deployï¼å°çæçç«ç¹ææ¡£é¨ç½²å°ç¹å®çæå¡å¨ä¸
***
### æ§è¡äºä»¶
Maven çæä»¶ç¨æ¥æ§è¡çå½å¨æä¸çç¸å
³äºä»¶
- æä»¶ä¸çå½å¨æå
çé¶æ®µç»å®ï¼å¨æ§è¡å°å¯¹åºçå½å¨ææ¶æ§è¡å¯¹åºçæä»¶
- Maven é»è®¤å¨å个çå½å¨æä¸é½ç»å®äºé¢å
设å®çæä»¶æ¥å®æç¸åºåè½
- æä»¶è¿å¯ä»¥å®æä¸äºèªå®ä¹åè½
```xml
org.apache.maven.plugins
maven-source-plugin
2.2.1
jar
test-jar
generate-test-resources
```
***
## 模åå¼å
### æå
å·¥ç¨æ¨¡å䏿¨¡åååï¼

* ssm_pojo æå
* æ°å»ºæ¨¡åï¼æ·è´åå§é¡¹ç®ä¸å¯¹åºçç¸å
³å
å®¹å° ssm_pojo 模åä¸
* å®ä½ç±»ï¼Userï¼
* é
ç½®æä»¶ï¼æ ï¼
* ssm_dao æå
* æ°å»ºæ¨¡å
* æ·è´åå§é¡¹ç®ä¸å¯¹åºçç¸å
³å
å®¹å° ssm_dao 模åä¸
- æ°æ®å±æ¥å£ï¼UserDaoï¼
- é
ç½®æä»¶ï¼ä¿ç䏿°æ®å±ç¸å
³é
ç½®æä»¶(3 个ï¼
- 注æï¼å页æä»¶å¨é
ç½®ä¸ä¸ SqlSessionFactoryBean ç»å®ï¼éè¦ä¿ç
- pom.xmlï¼å¼å
¥æ°æ®å±ç¸å
³åæ å³å¯ï¼å é¤ SpringMVC ç¸å
³åæ
- Spring
- MyBatis
- Spring æ´å MyBatis
- MySQL
- druid
- pagehelper
- ç´æ¥ä¾èµ ssm_pojoï¼å¯¹ ssm_pojo æ¨¡åæ§è¡ install æä»¤ï¼å°å
¶å®è£
å°æ¬å°ä»åºï¼
```xml
demo
ssm_pojo
1.0-SNAPSHOT
```
* ssm_service æå
* æ°å»ºæ¨¡å
* æ·è´åå§é¡¹ç®ä¸å¯¹åºçç¸å
³å
å®¹å° ssm_service 模åä¸
- ä¸å¡å±æ¥å£ä¸å®ç°ç±»ï¼UserServiceãUserServiceImplï¼
- é
ç½®æä»¶ï¼ä¿ç䏿°æ®å±ç¸å
³é
ç½®æä»¶(1 个ï¼
- pom.xmlï¼å¼å
¥æ°æ®å±ç¸å
³åæ å³å¯ï¼å é¤ SpringMVC ç¸å
³åæ
- spring
- junit
- spring æ´å junit
- ç´æ¥ä¾èµ ssm_daoï¼å¯¹ ssm_dao æ¨¡åæ§è¡ install æä»¤ï¼å°å
¶å®è£
å°æ¬å°ä»åºï¼
- é´æ¥ä¾èµ ssm_pojoï¼ç± ssm_dao 模åè´è´£ä¾èµå
³ç³»ç建ç«ï¼
- ä¿®æ¹ service 模å Spring æ ¸å¿é
ç½®æä»¶åï¼æ·»å 模ååç§°ï¼æ ¼å¼ï¼applicationContext-service.xml
- ä¿®æ¹ dao 模å Spring æ ¸å¿é
ç½®æä»¶åï¼æ·»å 模ååç§°ï¼æ ¼å¼ï¼applicationContext-dao.xml
- ä¿®æ¹åå
æµè¯å¼å
¥çé
ç½®æä»¶åç§°ï¼ç±å个æä»¶ä¿®æ¹ä¸ºå¤ä¸ªæä»¶
* ssm_control æå
* æ°å»ºæ¨¡åï¼ä½¿ç¨ webapp 模æ¿ï¼
* æ·è´åå§é¡¹ç®ä¸å¯¹åºçç¸å
³å
å®¹å° ssm_controller 模åä¸
- ç°å±æ§å¶å¨ç±»ä¸ç¸å
³è®¾ç½®ç±»ï¼UserControllerãå¼å¸¸ç¸å
³â¦â¦ï¼
- é
ç½®æä»¶ï¼ä¿çä¸è¡¨ç°å±ç¸å
³é
ç½®æä»¶(1 个ï¼ãæå¡å¨ç¸å
³é
ç½®æä»¶ï¼1 个ï¼
- pom.xmlï¼å¼å
¥æ°æ®å±ç¸å
³åæ å³å¯ï¼å é¤ SpringMVC ç¸å
³åæ
- spring
- springmvc
- jackson
- servlet
- tomcat æå¡å¨æä»¶
- ç´æ¥ä¾èµ ssm_serviceï¼å¯¹ ssm_service æ¨¡åæ§è¡ install æä»¤ï¼å°å
¶å®è£
å°æ¬å°ä»åºï¼
- é´æ¥ä¾èµ ssm_daoãssm_pojo
```xml
demo
ssm_service
1.0-SNAPSHOT
```
- ä¿®æ¹ web.xml é
ç½®æä»¶ä¸å è½½ Spring ç¯å¢çé
ç½®æä»¶åç§°ï¼ä½¿ç¨*éé
ï¼å è½½ææ applicationContext- å¼å§çé
ç½®æä»¶ï¼
```xml
contextConfigLocation
classpath*:applicationContext-*.xml
```
- spring-mvc
```xml
```
***
### èå
ä½ç¨ï¼èåç¨äºå¿«éæå»º Maven å·¥ç¨ï¼ä¸æ¬¡æ§æå»ºå¤ä¸ªé¡¹ç®/模å
å¶ä½æ¹å¼ï¼
- å建ä¸ä¸ªç©ºæ¨¡åï¼æå
ç±»åå®ä¹ä¸º pom
```xml
pom
```
- å®ä¹å½å模åè¿è¡æå»ºæä½æ¶å
³èçå
¶ä»æ¨¡ååç§°
```xml
4.0.0
demo
ssm
1.0-SNAPSHOT
pom
../ssm_pojo
../ssm_dao
../ssm_service
../ssm_controller
```
注æäºé¡¹ï¼åä¸èåæä½ç模åæç»æ§è¡é¡ºåºä¸æ¨¡åé´çä¾èµå
³ç³»æå
³ï¼ä¸é
ç½®é¡ºåºæ å
³
***
### ç»§æ¿
ä½ç¨ï¼éè¿ç»§æ¿å¯ä»¥å®ç°å¨åå·¥ç¨ä¸æ²¿ç¨ç¶å·¥ç¨ä¸çé
ç½®
- Maven ä¸çç»§æ¿ä¸ Java ä¸çç»§æ¿ç¸ä¼¼ï¼å¨åå·¥ç¨ä¸é
置继æ¿å
³ç³»
å¶ä½æ¹å¼ï¼
- å¨åå·¥ç¨ä¸å£°æå
¶ç¶å·¥ç¨åæ ä¸å¯¹åºçä½ç½®
```xml
com.seazean
ssm
1.0-SNAPSHOT
../ssm/pom.xml
```
- ç»§æ¿ä¾èµçå®ä¹ï¼å¨ç¶å·¥ç¨ä¸å®ä¹ä¾èµç®¡ç
```xml
org.springframework
spring-context
5.1.9.RELEASE
```
- ç»§æ¿ä¾èµç使ç¨ï¼å¨åå·¥ç¨ä¸å®ä¹ä¾èµå
³ç³»ï¼**æ é声æä¾èµçæ¬**ï¼çæ¬åç
§ç¶å·¥ç¨ä¸ä¾èµççæ¬
```xml
org.springframework
spring-context
```
- ç»§æ¿çèµæºï¼
```xml
groupIdï¼é¡¹ç®ç»IDï¼é¡¹ç®åæ çæ ¸å¿å
ç´
versionï¼é¡¹ç®çæ¬ï¼é¡¹ç®åæ çæ ¸å¿å ç´
descriptionï¼é¡¹ç®çæè¿°ä¿¡æ¯
organizationï¼é¡¹ç®çç»ç»ä¿¡æ¯
inceptionYearï¼é¡¹ç®çåå§å¹´ä»½
urlï¼é¡¹ç®çURLå°å
developersï¼é¡¹ç®çå¼åè
ä¿¡æ¯
contributorsï¼é¡¹ç®çè´¡ç®è
ä¿¡æ¯
distributionManagementï¼é¡¹ç®çé¨ç½²é
ç½®
issueManagementï¼é¡¹ç®ç缺é·è·è¸ªç³»ç»ä¿¡æ¯
ciManagementï¼é¡¹ç®çæç»éæç³»ç»ä¿¡æ¯
scmï¼é¡¹ç®ççæ¬æ§å¶ç³»ç»ä¿¡æ¯
malilingListsï¼é¡¹ç®çé®ä»¶å表信æ¯
propertiesï¼èªå®ä¹çMaven屿§
dependenciesï¼é¡¹ç®çä¾èµé
ç½®
dependencyManagementï¼é¡¹ç®çä¾èµç®¡çé
ç½®
repositoriesï¼é¡¹ç®çä»åºé
ç½®
buildï¼å
æ¬é¡¹ç®çæºç ç®å½é
ç½®ãè¾åºç®å½é
ç½®ãæä»¶é
ç½®ãæä»¶ç®¡çé
ç½®ç
reportingï¼å
æ¬é¡¹ç®çæ¥åè¾åºç®å½é
ç½®ãæ¥åæä»¶é
ç½®ç
```
- ç»§æ¿ä¸èåï¼
ä½ç¨ï¼
- èåç¨äºå¿«éæå»ºé¡¹ç®
- ç»§æ¿ç¨äºå¿«éé
ç½®
ç¸åç¹ï¼
- èåä¸ç»§æ¿ç pom.xml æä»¶æå
æ¹å¼å为 pomï¼å¯ä»¥å°ä¸¤ç§å
³ç³»å¶ä½å°åä¸ä¸ª pom æä»¶ä¸
- èåä¸ç»§æ¿åå±äºè®¾è®¡å模åï¼å¹¶æ å®é
çæ¨¡åå
容
ä¸åç¹ï¼
- è忝å¨å½å模åä¸é
ç½®å
³ç³»ï¼èåå¯ä»¥æç¥å°åä¸èåçæ¨¡åæåªäº
- ç»§æ¿æ¯å¨å模åä¸é
ç½®å
³ç³»ï¼ç¶æ¨¡åæ æ³æç¥åªäºå模åç»§æ¿äºèªå·±
***
### 屿§
* çæ¬ç»ä¸çéè¦æ§ï¼

* 屿§ç±»å«ï¼
1. èªå®ä¹å±æ§
2. å
ç½®å±æ§
3. setting 屿§
4. Java ç³»ç»å±æ§
5. ç¯å¢åé屿§
* èªå®ä¹å±æ§ï¼
ä½ç¨ï¼çåäºå®ä¹åéï¼æ¹ä¾¿ç»ä¸ç»´æ¤
å®ä¹æ ¼å¼ï¼
```xml
5.1.9.RELEASE
4.12
```
- èåä¸ç»§æ¿ç pom.xml æä»¶æå
æ¹å¼å为 pomï¼å¯ä»¥å°ä¸¤ç§å
³ç³»å¶ä½å°åä¸ä¸ª pom æä»¶ä¸
- èåä¸ç»§æ¿åå±äºè®¾è®¡å模åï¼å¹¶æ å®é
çæ¨¡åå
容
è°ç¨æ ¼å¼ï¼
```xml
org.springframework
spring-context
${spring.version}
```
* å
ç½®å±æ§ï¼
ä½ç¨ï¼ä½¿ç¨ Maven å
ç½®å±æ§ï¼å¿«éé
ç½®
è°ç¨æ ¼å¼ï¼
```xml
${project.basedir} or ${project.basedir} ${version} or ${project.version}
```
* vresion æ¯ 1.0-SNAPSHOT
```xml
demo
ssm
1.0-SNAPSHOT
```
* setting 屿§
- ä½¿ç¨ Maven é
ç½®æä»¶ setting.xml ä¸çæ ç¾å±æ§ï¼ç¨äºå¨æé
ç½®
è°ç¨æ ¼å¼ï¼
```xml
${settings.localRepository}
```
* Java ç³»ç»å±æ§ï¼
ä½ç¨ï¼è¯»å Java ç³»ç»å±æ§
è°ç¨æ ¼å¼ï¼
```xml
${user.home}
```
ç³»ç»å±æ§æ¥è¯¢æ¹å¼ cmd å½ä»¤ï¼
```sh
mvn help:system
```
* ç¯å¢åé屿§
ä½ç¨ï¼ä½¿ç¨ Maven é
ç½®æä»¶ setting.xml ä¸çæ ç¾å±æ§ï¼ç¨äºå¨æé
ç½®
è°ç¨æ ¼å¼ï¼
```xml
${env.JAVA_HOME}
```
ç¯å¢åé屿§æ¥è¯¢æ¹å¼ï¼
```sh
mvn help:system
```
***
### å·¥ç¨çæ¬
SNAPSHOTï¼å¿«ç
§çæ¬ï¼
- 项ç®å¼åè¿ç¨ä¸ï¼ä¸ºæ¹ä¾¿å¢éæååä½ï¼è§£å³æ¨¡åé´ç¸äºä¾èµåæ¶æ¶æ´æ°çé®é¢ï¼å¼åè
对æ¯ä¸ªæ¨¡åè¿è¡æå»ºçæ¶åï¼è¾åºçä¸´æ¶æ§çæ¬å«å¿«ç
§çæ¬ï¼æµè¯é¶æ®µçæ¬ï¼
- å¿«ç
§çæ¬ä¼éçå¼åçè¿å±ä¸ææ´æ°
RELEASEï¼åå¸çæ¬ï¼
- 项ç®å¼åå°è¿å
¥é¶æ®µéç¨ç¢åï¼åå¢éå¤é¨åå¸è¾ä¸ºç¨³å®ççæ¬ï¼è¿ç§çæ¬æå¯¹åºçæä»¶æä»¶æ¯ç¨³å®çï¼å³ä¾¿è¿è¡åè½çåç»å¼åï¼ä¹ä¸ä¼æ¹åå½ååå¸çæ¬å
容ï¼è¿ç§çæ¬ç§°ä¸ºåå¸çæ¬
约å®è§èï¼
- <ä¸»çæ¬>.<æ¬¡çæ¬>.<å¢éçæ¬>.<éç¨ç¢çæ¬>
- ä¸»çæ¬ï¼è¡¨ç¤ºé¡¹ç®éå¤§æ¶æçåæ´ï¼å¦ï¼Spring5 ç¸è¾äº Spring4 çè¿ä»£
- æ¬¡çæ¬ï¼è¡¨ç¤ºæè¾å¤§çåè½å¢å åååï¼æè
å
¨é¢ç³»ç»å°ä¿®å¤æ¼æ´
- å¢éçæ¬ï¼è¡¨ç¤ºæéå¤§æ¼æ´çä¿®å¤
- éç¨ç¢çæ¬ï¼è¡¨æä¸ä¸ªçæ¬çéç¨ç¢ï¼çæ¬å
é¨ï¼ãè¿æ ·ççæ¬åä¸ä¸ä¸ªæ£å¼çæ¬ç¸æ¯ï¼ç¸å¯¹æ¥è¯´ä¸æ¯å¾ç¨³å®ï¼æå¾
æ´å¤çæµè¯
***
### èµæºé
ç½®
ä½ç¨ï¼å¨ä»»æé
ç½®æä»¶ä¸å è½½ pom æä»¶ä¸å®ä¹ç屿§
* ç¶æä»¶ pom.xml
```xml
jdbc:mysql://192.168.0.137:3306/ssm_db?useSSL=false
```
- å¼å¯é
ç½®æä»¶å è½½ pom 屿§ï¼
```xml
${project.basedir}/src/main/resources
true
```
* properties æä»¶ä¸è°ç¨æ ¼å¼ï¼
```properties
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=${jdbc.url}
jdbc.username=rootjdbc.password=123456
```
***
### å¤ç¯å¢é
ç½®
* ç¯å¢é
ç½®
```xml
pro_env
jdbc:mysql://127.1.1.1:3306/ssm_db
true
dev_env
â¦â¦
```
* å è½½æå®ç¯å¢
ä½ç¨ï¼å è½½æå®ç¯å¢é
ç½®
è°ç¨æ ¼å¼ï¼
```sh
mvn æä»¤ âP ç¯å¢å®ä¹id
```
èä¾ï¼
```sh
mvn install âP pro_env
```
***
## è·³è¿æµè¯
å½ä»¤ï¼
```sh
mvn æä»¤ âD skipTests
```
注æäºé¡¹ï¼æ§è¡çæä»¤çå½å¨æå¿
é¡»å
嫿µè¯ç¯è
IEDA çé¢ï¼

é
置跳è¿ï¼
```xml
maven-surefire-plugin
2.22.1
true
**/User*Test.java
**/User*TestCase.java
```
***
## ç§æ
### Nexus
Nexus æ¯ Sonatype å
¬å¸ç䏿¬¾ Maven ç§æäº§å
ä¸è½½å°åï¼https://help.sonatype.com/repomanager3/download
å¯å¨æå¡å¨ï¼å½ä»¤è¡å¯å¨ï¼ï¼
```sh
nexus.exe /run nexus
```
è®¿é®æå¡å¨ï¼é»è®¤ç«¯å£ï¼8081ï¼ï¼
```sh
http://localhost:8081
```
ä¿®æ¹åºç¡é
置信æ¯
- å®è£
è·¯å¾ä¸ etc ç®å½ä¸ nexus-default.properties æä»¶ä¿åæ nexus åºç¡é
置信æ¯ï¼ä¾å¦é»è®¤è®¿é®ç«¯å£
ä¿®æ¹æå¡å¨è¿è¡é
置信æ¯
- å®è£
è·¯å¾ä¸ bin ç®å½ä¸ nexus.vmoptions æä»¶ä¿åæ nexus æå¡å¨å¯å¨çé
置信æ¯ï¼ä¾å¦é»è®¤å ç¨å
å空é´
***
### èµæºæä½

ä»åºåç±»ï¼
* 宿主ä»åº hosted
* ä¿åæ æ³ä»ä¸å¤®ä»åºè·åçèµæº
* èªä¸»ç å
* ç¬¬ä¸æ¹é弿ºé¡¹ç®
* 代çä»åº proxy
* 代çè¿ç¨ä»åºï¼éè¿ nexus 访é®å
¶ä»å
Œ
±ä»åºï¼ä¾å¦ä¸å¤®ä»åº
* ä»åºç» group
* å°è¥å¹²ä¸ªä»åºç»æä¸ä¸ªç¾¤ç»ï¼ç®åé
ç½®
* ä»åºç»ä¸è½ä¿åèµæºï¼å±äºè®¾è®¡åä»åº
èµæºä¸ä¼ ï¼ä¸ä¼ èµæºæ¶æä¾å¯¹åºçä¿¡æ¯
- ä¿åçä½ç½®ï¼å®¿ä¸»ä»åºï¼
- èµæºæä»¶
- 对åºåæ
***
### IDEAæä½
#### ä¸ä¼ ä¸è½½

***
#### 访é®ç§æ
##### æ¬å°è®¿é®
é
ç½®æ¬å°ä»åºè®¿é®ç§æçæéï¼setting.xmlï¼
```xml
heima-release
admin
admin
heima-snapshots
admin
admin
```
é
ç½®æ¬å°ä»åºèµæºæ¥æºï¼setting.xmlï¼
```xml
nexus-heima
*
http://localhost:8081/repository/maven-public/
```
***
##### å·¥ç¨è®¿é®
é
ç½®å½å项ç®è®¿é®ç§æä¸ä¼ èµæºçä¿åä½ç½®ï¼pom.xmlï¼
```xml
heima-release
http://localhost:8081/repository/heima-release/
heima-snapshots
http://localhost:8081/repository/heima-snapshots/
```
åå¸èµæºå°ç§æå½ä»¤
```sh
mvn deploy
```
***
## æ¥å¿
### Log4j
ç¨åºä¸çæ¥å¿å¯ä»¥ç¨æ¥è®°å½ç¨åºå¨è¿è¡æ¶åç详æ
ï¼å¹¶å¯ä»¥è¿è¡æ°¸ä¹
åå¨ã
| | è¾åºè¯å¥ | æ¥å¿ææ¯ |
| -------- | -------------------------- | ---------------------------------------- |
| åæ¶æ¥å¿ | éè¦ä¿®æ¹ä»£ç ï¼çµæ´»æ§æ¯è¾å·® | ä¸éè¦ä¿®æ¹ä»£ç ï¼çµæ´»æ§æ¯è¾å¥½ |
| è¾åºä½ç½® | åªè½æ¯æ§å¶å° | å¯ä»¥å°æ¥å¿ä¿¡æ¯åå
¥å°æä»¶æè
æ°æ®åºä¸ |
| å¤çº¿ç¨ | åä¸å¡ä»£ç å¤äºä¸ä¸ªçº¿ç¨ä¸ | å¤çº¿ç¨æ¹å¼è®°å½æ¥å¿ï¼ä¸å½±åä¸å¡ä»£ç çæ§è½ |
Log4j æ¯ Apache çä¸ä¸ªå¼æºé¡¹ç®ãä½¿ç¨ Log4jï¼éè¿ä¸ä¸ªé
ç½®æä»¶æ¥çµæ´»å°è¿è¡é
ç½®ï¼èä¸éè¦ä¿®æ¹åºç¨ç代ç ãæä»¬å¯ä»¥æ§å¶æ¥å¿ä¿¡æ¯è¾éçç®çå°æ¯æ§å¶å°ãæä»¶çä½ç½®ï¼ä¹å¯ä»¥æ§å¶æ¯ä¸æ¡æ¥å¿çè¾åºæ ¼å¼ã
***
### é
ç½®æä»¶
é
ç½®æä»¶çä¸ä¸ªæ ¸å¿ï¼
+ é
ç½®æ ¹ Logger
+ æ ¼å¼ï¼log4j.rootLogger=æ¥å¿çº§å«ï¼appenderName1ï¼appenderName2ï¼â¦
+ æ¥å¿çº§å«ï¼å¸¸è§çäºä¸ªçº§å«ï¼**DEBUG < INFO < WARN < ERROR < FATAL**ï¼å¯ä»¥èªå®ä¹ï¼
Log4j è§åï¼åªè¾åºçº§å«ä¸ä½äºè®¾å®çº§å«çæ¥å¿ä¿¡æ¯
+ appenderName1ï¼æå®æ¥å¿ä¿¡æ¯è¦è¾åºå°åãå¯ä»¥åæ¶æå®å¤ä¸ªè¾åºç®çå°ï¼ç¨éå·éå¼ï¼
ä¾å¦ï¼log4j.rootLoggerï¼INFOï¼caï¼fa
+ Appendersï¼è¾åºæºï¼ï¼æ¥å¿è¦è¾åºçå°æ¹ï¼å¦æ§å¶å°ï¼Consoleï¼ãæä»¶ï¼Filesï¼ç
+ Appenders åå¼ï¼
+ org.apache.log4j.ConsoleAppenderï¼æ§å¶å°ï¼
+ org.apache.log4j.FileAppenderï¼æä»¶ï¼
+ ConsoleAppender 常ç¨åæ°
+ `ImmediateFlush=true`ï¼è¡¨ç¤ºæææ¶æ¯é½ä¼è¢«ç«å³è¾åºï¼è®¾ä¸º false åä¸è¾åºï¼é»è®¤å¼æ¯ true
+ `Target=System.err`ï¼é»è®¤å¼æ¯ System.out
+ FileAppender常ç¨çé项
+ `ImmediateFlush=true`ï¼è¡¨ç¤ºæææ¶æ¯é½ä¼è¢«ç«å³è¾åºã设为 false åä¸è¾åºï¼é»è®¤å¼æ¯ true
+ `Append=false`ï¼true è¡¨ç¤ºå°æ¶æ¯æ·»å 尿宿件ä¸ï¼åæ¥çæ¶æ¯ä¸è¦çãé»è®¤å¼æ¯ true
+ `File=E:/logs/logging.log4j`ï¼æå®æ¶æ¯è¾åºå° logging.log4j æä»¶ä¸
+ Layouts (å¸å±)ï¼æ¥å¿è¾åºçæ ¼å¼ï¼å¸¸ç¨çå¸å±ç®¡çå¨ï¼
+ org.apache.log4j.PatternLayoutï¼å¯ä»¥çµæ´»å°æå®å¸å±æ¨¡å¼ï¼
+ org.apache.log4j.SimpleLayoutï¼å
嫿¥å¿ä¿¡æ¯ç级å«åä¿¡æ¯å符串ï¼
+ org.apache.log4j.TTCCLayoutï¼å
嫿¥å¿äº§ççæ¶é´ã线ç¨ãç±»å«çä¿¡æ¯ï¼
+ PatternLayout 常ç¨çé项
***
### æ¥å¿åºç¨
* log4j çé
ç½®æä»¶,åå为 log4j.properties, æ¾å¨ src æ ¹ç®å½ä¸
```properties
log4j.rootLogger=I
### direct log messages to my ###
log4j.appender.my=org.apache.log4j.ConsoleAppender
log4j.appender.my.ImmediateFlush = true
log4j.appender.my.Target=System.out
log4j.appender.my.layout=org.apache.log4j.PatternLayout
log4j.appender.my.layout.ConversionPattern=%d %t %5p %c{1}:%L - %m%n
# fileAppenderæ¼ç¤º
log4j.appender.fileAppender=org.apache.log4j.FileAppender
log4j.appender.fileAppender.ImmediateFlush = true
log4j.appender.fileAppender.Append=true
log4j.appender.fileAppender.File=E:/log4j-log.log
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=%d %5p %c{1}:%L - %m%n
```
* æµè¯ç±»
```java
// æµè¯ç±»
public class Log4JTest01 {
//使ç¨log4jçapiæ¥è·åæ¥å¿ç对象
//å¼ç«¯ï¼å¦æä»¥åæä»¬æ´æ¢æ¥å¿çå®ç°ç±»ï¼é£ä¹ä¸é¢ç代ç å°±éè¦è·çæ¹
//䏿¨è使ç¨
//private static final Logger LOGGER = Logger.getLogger(Log4JTest01.class);
//使ç¨slf4jéé¢çapiæ¥è·åæ¥å¿ç对象
//好å¤ï¼å¦æä»¥åæä»¬æ´æ¢æ¥å¿çå®ç°ç±»ï¼é£ä¹ä¸é¢ç代ç ä¸éè¦è·çä¿®æ¹
//æ¨è使ç¨
private static final Logger LOGGER = LoggerFactory.getLogger(Log4JTest01.class);
public static void main(String[] args) {
//1.导å
¥jarå
//2.ç¼åé
ç½®æä»¶
//3.å¨ä»£ç ä¸è·åæ¥å¿ç对象
//4.æç
§æ¥å¿çº§å«è®¾ç½®æ¥å¿ä¿¡æ¯
LOGGER.debug("debug级å«çæ¥å¿");
LOGGER.info("info级å«çæ¥å¿");
LOGGER.warn("warn级å«çæ¥å¿");
LOGGER.error("error级å«çæ¥å¿");
}
}
```
***
# Netty
## åºæ¬ä»ç»
Netty æ¯ä¸ä¸ªå¼æ¥äºä»¶é©±å¨çç½ç»åºç¨ç¨åºæ¡æ¶ï¼ç¨äºå¿«éå¼åå¯ç»´æ¤ã髿§è½çç½ç»æå¡å¨å客æ·ç«¯
Netty å®ç½ï¼https://netty.io/
Netty ç对 JDK èªå¸¦ç NIO ç API è¿è¡å°è£
ï¼è§£å³ä¸è¿°é®é¢ï¼ä¸»è¦ç¹ç¹æï¼
- 设计ä¼é
ï¼éç¨äºåç§ä¼ è¾ç±»åçç»ä¸ APIï¼ é»å¡åéé»å¡ Socket åºäºçµæ´»ä¸å¯æ©å±çäºä»¶æ¨¡å
- ä½¿ç¨æ¹ä¾¿ï¼è¯¦ç»è®°å½ç Javadocãç¨æ·æåå示ä¾ï¼æ²¡æå
¶ä»ä¾èµé¡¹
- 髿§è½ï¼ååéæ´é«ï¼å»¶è¿æ´ä½ï¼åå°èµæºæ¶èï¼æå°åä¸å¿
è¦çå
åå¤å¶
- å®å
¨ï¼å®æ´ç SSL/TLS å StartTLS æ¯æ
Netty çåè½ç¹æ§ï¼
* ä¼ è¾æå¡ï¼æ¯æ BIO å NIO
* 容å¨éæï¼æ¯æ OSGIãJBossMCãSpringãGuice 容å¨
* åè®®æ¯æï¼HTTPãProtobufãäºè¿å¶ãææ¬ãWebSocket çä¸ç³»ååè®®é½æ¯æï¼ä¹æ¯æéè¿å®è¡ç¼ç è§£ç é»è¾æ¥å®ç°èªå®ä¹åè®®
* Core æ ¸å¿ï¼å¯æ©å±äºä»¶æ¨¡åãéç¨éä¿¡ APIãæ¯æé¶æ·è´ç ByteBuf ç¼å²å¯¹è±¡
***
## çº¿ç¨æ¨¡å
### é»å¡æ¨¡å
ä¼ ç»é»å¡å I/O 模å¼ï¼æ¯ä¸ªè¿æ¥é½éè¦ç¬ç«ç线ç¨å®ææ°æ®çè¾å
¥ï¼ä¸å¡å¤çï¼æ°æ®è¿å
模å缺ç¹ï¼
- å½å¹¶åæ°è¾å¤§æ¶ï¼éè¦å建大éçº¿ç¨æ¥å¤çè¿æ¥ï¼ç³»ç»èµæºå ç¨è¾å¤§
- è¿æ¥å»ºç«åï¼å¦æå½åçº¿ç¨ææ¶æ²¡ææ°æ®å¯è¯»ï¼å线ç¨å°±é»å¡å¨ read æä½ä¸ï¼é æçº¿ç¨èµæºæµªè´¹
åèæç« ï¼https://www.jianshu.com/p/2965fca6bb8f
***
### Reactor
#### è®¾è®¡ææ³
Reactor 模å¼ï¼éè¿ä¸ä¸ªæå¤ä¸ªè¾å
¥åæ¶ä¼ éç»æå¡å¤çå¨ç**äºä»¶é©±å¨å¤ç模å¼**ã æå¡ç«¯ç¨åºå¤çä¼ å
¥çå¤è·¯è¯·æ±ï¼å¹¶å°å®ä»¬åæ¥åæ´¾ç»å¯¹åºçå¤ç线ç¨ï¼Reactor 模å¼ä¹å« Dispatcher 模å¼ï¼å³ I/O å¤è·¯å¤ç¨ç»ä¸çå¬äºä»¶ï¼æ¶å°äºä»¶åååï¼Dispatch ç»æçº¿ç¨ï¼
**I/O å¤ç¨ç»åçº¿ç¨æ± **ï¼å°±æ¯ Reactor 模å¼åºæ¬è®¾è®¡ææ³ï¼
Reactor 模å¼å
³é®ç»æï¼
- Reactorï¼å¨ä¸ä¸ªåç¬ç线ç¨ä¸è¿è¡ï¼è´è´£**çå¬åååäºä»¶**ï¼ååç»éå½çå¤çç¨åºæ¥å¯¹ I/O äºä»¶ååºååº
- Handlerï¼å¤çç¨åºæ§è¡ I/O è¦å®æçå®é
äºä»¶ï¼Reactor éè¿è°åº¦éå½çå¤çç¨åºæ¥ååº I/O äºä»¶ï¼å¤çç¨åºæ§è¡**éé»å¡æä½**
Reactor 模å¼å
·æå¦ä¸çä¼ç¹ï¼
- ååºå¿«ï¼ä¸å¿
为åä¸ªåæ¥æ¶é´æé»å¡ï¼è½ç¶ Reactor æ¬èº«ä¾ç¶æ¯åæ¥ç
- ç¼ç¨ç¸å¯¹ç®åï¼å¯ä»¥æå¤§ç¨åº¦çé¿å
夿çå¤çº¿ç¨å忥é®é¢ï¼å¹¶ä¸é¿å
äºå¤çº¿ç¨/è¿ç¨ç忢å¼é
- 坿©å±æ§ï¼å¯ä»¥æ¹ä¾¿çéè¿å¢å Reactor å®ä¾ä¸ªæ°æ¥å
åå©ç¨ CPU èµæº
- å¯å¤ç¨æ§ï¼Reactor æ¨¡åæ¬èº«ä¸å
·ä½äºä»¶å¤çé»è¾æ å
³ï¼å
·æå¾é«çå¤ç¨æ§
æ ¹æ® Reactor çæ°éåå¤çèµæºæ± 线ç¨çæ°éä¸åï¼æä¸ç§å
¸åçå®ç°ï¼
- å Reactor å线ç¨
- å Reactor å¤çº¿ç¨
- ä¸»ä» Reactor å¤çº¿ç¨
***
#### åRå线ç¨
Reactor 对象éè¿ select çæ§å®¢æ·ç«¯è¯·æ±äºä»¶ï¼æ¶å°äºä»¶åéè¿ dispatch è¿è¡ååï¼
* 妿æ¯å»ºç«è¿æ¥è¯·æ±äºä»¶ï¼åç± Acceptor éè¿ accept å¤çè¿æ¥è¯·æ±ï¼ç¶åå建ä¸ä¸ª Handler 对象å¤çè¿æ¥å®æåçåç»ä¸å¡å¤ç
* 妿䏿¯å»ºç«è¿æ¥äºä»¶ï¼å Reactor ä¼ååç»è¿æ¥å¯¹åºç Handler æ¥ååºï¼Handler ä¼å®æ readãä¸å¡å¤çãsend ç宿´æµç¨
说æï¼**Handler å Acceptor å±äºåä¸ä¸ªçº¿ç¨**
模åä¼ç¹ï¼æ¨¡åç®åï¼æ²¡æå¤çº¿ç¨ãè¿ç¨éä¿¡ãç«äºçé®é¢ï¼å
¨é¨é½å¨ä¸ä¸ªçº¿ç¨ä¸å®æ
模å缺ç¹ï¼
* æ§è½é®é¢ï¼åªæä¸ä¸ªçº¿ç¨ï¼æ æ³åæ¥å¤æ ¸ CPU çæ§è½ï¼Handler å¨å¤çæä¸ªè¿æ¥ä¸çä¸å¡æ¶ï¼æ´ä¸ªè¿ç¨æ æ³å¤çå
¶ä»è¿æ¥äºä»¶ï¼å¾å®¹æå¯¼è´æ§è½ç¶é¢
* å¯é æ§é®é¢ï¼çº¿ç¨æå¤è·é£ï¼æè
è¿å
¥æ»å¾ªç¯ï¼ä¼å¯¼è´æ´ä¸ªç³»ç»é信模åä¸å¯ç¨ï¼ä¸è½æ¥æ¶åå¤çå¤é¨æ¶æ¯ï¼é æèç¹æ
é
使ç¨åºæ¯ï¼å®¢æ·ç«¯çæ°éæéï¼ä¸å¡å¤çé常快éï¼æ¯å¦ Redisï¼ä¸å¡å¤ççæ¶é´å¤æåº¦ O(1)
***
#### åRå¤çº¿ç¨
æ§è¡æµç¨éåå Reactor å线ç¨ï¼ä¸åçæ¯ï¼
* Handler åªè´è´£ååºäºä»¶ï¼ä¸åå
·ä½ä¸å¡å¤çï¼éè¿ read è¯»åæ°æ®åï¼ä¼ååç»åé¢ç Worker çº¿ç¨æ± è¿è¡ä¸å¡å¤ç
* Worker çº¿ç¨æ± ä¼åé
ç¬ç«ç线ç¨å®æçæ£çä¸å¡å¤çï¼å°ååºç»æåç» Handler è¿è¡å¤çï¼æåç± Handler æ¶å°ååºç»æåéè¿ send å°ååºç»æè¿åç» Client
模åä¼ç¹ï¼å¯ä»¥å
åå©ç¨å¤æ ¸ CPU çå¤çè½å
模å缺ç¹ï¼
* å¤çº¿ç¨æ°æ®å
±äº«åè®¿é®æ¯è¾å¤æ
* Reactor æ¿æ
ææäºä»¶ççå¬åååºï¼å¨å线ç¨ä¸è¿è¡ï¼é«å¹¶ååºæ¯ä¸å®¹ææä¸ºæ§è½ç¶é¢
***
#### 䏻仿¨¡å
éç¨å¤ä¸ª Reactor ï¼æ§è¡æµç¨ï¼
* Reactor ä¸»çº¿ç¨ MainReactor éè¿ select **çæ§å»ºç«è¿æ¥äºä»¶**ï¼æ¶å°äºä»¶åéè¿ Acceptor æ¥æ¶ï¼å¤ç建ç«è¿æ¥äºä»¶ï¼å¤ç宿å MainReactor ä¼å°è¿æ¥åé
ç» Reactor å线ç¨ç SubReactorï¼æå¤ä¸ªï¼å¤ç
* SubReactor å°è¿æ¥å å
¥è¿æ¥éåè¿è¡çå¬å
¶ä»äºä»¶ï¼å¹¶å建ä¸ä¸ª Handler ç¨äºå¤çè¯¥è¿æ¥çäºä»¶ï¼å½ææ°çäºä»¶åçæ¶ï¼SubReactor ä¼è°ç¨è¿æ¥å¯¹åºç Handler è¿è¡ååº
* Handler éè¿ read è¯»åæ°æ®åï¼ä¼ååç» Worker çº¿ç¨æ± è¿è¡ä¸å¡å¤ç
* Worker çº¿ç¨æ± ä¼åé
ç¬ç«ç线ç¨å®æçæ£çä¸å¡å¤çï¼å°ååºç»æåç» Handler è¿è¡å¤çï¼æåç± Handler æ¶å°ååºç»æåéè¿ send å°ååºç»æè¿åç» Client
模åä¼ç¹
- **ç¶çº¿ç¨ä¸å线ç¨**çæ°æ®äº¤äºç®åèè´£æç¡®ï¼ç¶çº¿ç¨åªéè¦æ¥æ¶æ°è¿æ¥ï¼å线ç¨å®æåç»çä¸å¡å¤ç
- ç¶çº¿ç¨ä¸å线ç¨çæ°æ®äº¤äºç®åï¼Reactor 主线ç¨åªéè¦ææ°è¿æ¥ä¼ ç»å线ç¨ï¼åçº¿ç¨æ éè¿åæ°æ®
使ç¨åºæ¯ï¼Nginx ä¸»ä» Reactor å¤è¿ç¨æ¨¡åï¼Memcached 主ä»å¤çº¿ç¨ï¼Netty 主ä»å¤çº¿ç¨æ¨¡åçæ¯æ
***
### Proactor
Reactor 模å¼ä¸ï¼Reactor çå¾
æä¸ªäºä»¶çæä½ç¶æåçååï¼æä»¶æè¿°ç¬¦å¯è¯»åï¼socket å¯è¯»åï¼ï¼ç¶åæäºä»¶ä¼ éç»äºå
注åç Handler æ¥åå®é
ç读åæä½ï¼å
¶ä¸ç读åæä½é½éè¦åºç¨ç¨åºåæ¥æä½ï¼æä»¥ **Reactor æ¯éé»å¡åæ¥ç½ç»æ¨¡åï¼NIOï¼**
æ I/O æä½æ¹ä¸ºå¼æ¥ï¼äº¤ç»æä½ç³»ç»æ¥å®æå°±è½è¿ä¸æ¥æåæ§è½ï¼è¿å°±æ¯å¼æ¥ç½ç»æ¨¡å Proactorï¼AIOï¼ï¼
工使µç¨ï¼
* ProactorInitiator å建 Proactor å Handler 对象ï¼å¹¶å° Proactor å Handler éè¿ Asynchronous Operation Processorï¼AsyOptProcessorï¼æ³¨åå°å
æ ¸
* AsyOptProcessor å¤ç注å请æ±ï¼å¹¶å¤ç I/O æä½ï¼å®æI/Oåéç¥ Proactor
* Proactor æ ¹æ®ä¸åçäºä»¶ç±»ååè°ä¸åç Handler è¿è¡ä¸å¡å¤çï¼æåç± Handler 宿ä¸å¡å¤ç
对æ¯ï¼Reactor å¨äºä»¶åçæ¶å°±éç¥äºå
注åçå¤çå¨ï¼è¯»åå¨åºç¨ç¨åºçº¿ç¨ä¸å¤ç宿ï¼ï¼Proactor æ¯å¨äºä»¶åçæ¶åºäºå¼æ¥ I/O å®æè¯»åæä½ï¼å
æ ¸å®æï¼ï¼I/O 宿åæåè°åºç¨ç¨åºçå¤çå¨è¿è¡ä¸å¡å¤ç
模å¼ä¼ç¹ï¼å¼æ¥ I/O æ´å å
å忥 DMAï¼Direct Memory Access ç´æ¥å
åååï¼çä¼å¿
模å¼ç¼ºç¹ï¼
* ç¼ç¨å¤ææ§ï¼ç±äºå¼æ¥æä½æµç¨çäºä»¶çåå§ååäºä»¶å®æå¨æ¶é´å空é´ä¸é½æ¯ç¸äºå离çï¼å æ¤å¼å弿¥åºç¨ç¨åºæ´å 夿ï¼åºç¨ç¨åºè¿å¯è½å 为ååçæµæ§èå徿´å é¾ä»¥è°è¯
* å
å使ç¨ï¼ç¼å²åºå¨è¯»æåæä½çæ¶é´æ®µå
å¿
é¡»ä¿æä½ï¼å¯è½é ææç»çä¸ç¡®å®æ§ï¼å¹¶ä¸æ¯ä¸ªå¹¶åæä½é½è¦æ±æç¬ç«çç¼åï¼Reactor 模å¼å¨ socket åå¤å¥½è¯»æåä¹åæ¯ä¸è¦æ±å¼è¾ç¼åç
* æä½ç³»ç»æ¯æï¼Windows ä¸éè¿ IOCP å®ç°äºçæ£ç弿¥ I/Oï¼èå¨ Linux ç³»ç»ä¸ï¼Linux2.6 æå¼å
¥å¼æ¥ I/Oï¼ç®åè¿ä¸å®åï¼æä»¥å¨ Linux ä¸å®ç°é«å¹¶åç½ç»ç¼ç¨é½æ¯ä»¥ Reactor 模å为主
****
### Netty
Netty 主è¦åºäºä¸»ä» Reactors å¤çº¿ç¨æ¨¡ååäºä¸å®çæ¹è¿ï¼Netty ç工使¶æå¾ï¼
工使µç¨ï¼
1. Netty æ½è±¡åºä¸¤ç»çº¿ç¨æ± BossGroup ä¸é¨è´è´£æ¥æ¶å®¢æ·ç«¯çè¿æ¥ï¼WorkerGroup ä¸é¨è´è´£ç½ç»ç读å
2. BossGroup å WorkerGroup ç±»å齿¯ NioEventLoopGroupï¼è¯¥ Group ç¸å½äºä¸ä¸ªäºä»¶å¾ªç¯ç»ï¼å«æå¤ä¸ªäºä»¶å¾ªç¯ï¼æ¯ä¸ä¸ªäºä»¶å¾ªç¯æ¯ NioEventLoopï¼æä»¥å¯ä»¥æå¤ä¸ªçº¿ç¨
3. NioEventLoop 表示ä¸ä¸ª**循ç¯å¤çä»»å¡ç线ç¨**ï¼æ¯ä¸ª NioEventLoop 齿ä¸ä¸ª Selectorï¼ç¨äºçå¬ç»å®å¨å
¶ä¸ç Socket çé讯
4. æ¯ä¸ª Boss NioEventLoop å¾ªç¯æ§è¡çæ¥éª¤ï¼
- 轮询 accept äºä»¶
- å¤ç accept äºä»¶ï¼ä¸ client 建ç«è¿æ¥ï¼çæ NioScocketChannelï¼å¹¶å°å
¶**注åå°æä¸ª Worker ä¸**çæä¸ª NioEventLoop ä¸ç Selectorï¼è¿æ¥å°±ä¸ NioEventLoop ç»å®
- å¤çä»»å¡éåçä»»å¡ï¼å³ runAllTasks
5. æ¯ä¸ª Worker NioEventLoop å¾ªç¯æ§è¡çæ¥éª¤ï¼
- 轮询 readãwrite äºä»¶
- å¤ç I/O äºä»¶ï¼å³ readï¼write äºä»¶ï¼å¨å¯¹åº NioSocketChannel å¤ç
- å¤çä»»å¡éåçä»»å¡ï¼å³ runAllTasks
6. æ¯ä¸ª Worker NioEventLoop å¤çä¸å¡æ¶ï¼ä¼ä½¿ç¨ Pipelineï¼ç®¡éï¼ï¼Pipeline ä¸å
å«äº Channelï¼å³éè¿ Pipeline å¯ä»¥è·åå°å¯¹åºééï¼ç®¡éä¸ç»´æ¤äºå¾å¤çå¤çå¨ Handler
***
## åºæ¬å®ç°
å¼åç®åçæå¡å¨ç«¯å客æ·ç«¯ï¼åºæ¬ä»ç»ï¼
* Channel çè§£ä¸ºæ°æ®çééï¼æ msg ç解为æµå¨çæ°æ®ï¼æå¼å§è¾å
¥æ¯ ByteBufï¼ä½ç»è¿ Pipeline çå å·¥ï¼ä¼åæå
¶å®ç±»åå¯¹è±¡ï¼æåè¾åºååæ ByteBuf
* Handler çè§£ä¸ºæ°æ®çå¤çå·¥åºï¼Pipeline è´è´£åå¸äºä»¶ä¼ æç»æ¯ä¸ª Handlerï¼Handler 对èªå·±æå
´è¶£çäºä»¶è¿è¡å¤çï¼éåäºç¸åºäºä»¶å¤çæ¹æ³ï¼ï¼å Inbound å Outbound 两类
* EventLoop ç解为å¤çæ°æ®çæ§è¡è
ï¼æ¢å¯ä»¥æ§è¡ IO æä½ï¼ä¹å¯ä»¥è¿è¡ä»»å¡å¤çãæ¯ä¸ªæ§è¡è
æä»»å¡éåï¼éåéå¯ä»¥å æ¾å¤ä¸ª Channel çå¾
å¤çä»»å¡ï¼ä»»å¡å为æ®éä»»å¡ã宿¶ä»»å¡ãæç
§ Pipeline 顺åºï¼ä¾æ¬¡æç
§ Handler çè§åï¼ä»£ç ï¼å¤çæ°æ®
代ç å®ç°ï¼
* pom.xml
```xml
io.netty
netty-all
4.1.20.Final
```
* Server.java
```java
public class HelloServer {
public static void main(String[] args) {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup(2);
// 1. å¯å¨å¨ï¼è´è´£ç»è£
netty ç»ä»¶ï¼å¯å¨æå¡å¨
new ServerBootstrap()
// 2. 线ç¨ç»ï¼boss åªè´è´£ãå¤ç accept äºä»¶ãï¼ worker åªãè´è´£ channel ä¸ç读åã
.group(boss, worker)
//.option() // ç» ServerSocketChannel é
ç½®åæ°
//.childOption() // ç» SocketChannel é
ç½®åæ°
// 3. éæ©æå¡å¨ç ServerSocketChannel å®ç°
.channel(NioServerSocketChannel.class)
// 4. boss è´è´£å¤çè¿æ¥ï¼worker(child) è´è´£å¤ç读åï¼å³å®äºè½æ§è¡åªäºæä½(handler)
.childHandler(new ChannelInitializer() {
// 5. channel 代表å客æ·ç«¯è¿è¡æ°æ®è¯»åçéé Initializer åå§åï¼è´è´£æ·»å å«ç handler
// 7. è¿æ¥å»ºç«åï¼æ§è¡åå§åæ¹æ³
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// æ·»å å
·ä½ç handler
ch.pipeline().addLast(new StringDecoder());// å° ByteBuf 转æå符串
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { // èªå®ä¹ handler
// 读äºä»¶
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// æå°è½¬æ¢å¥½çå符串
System.out.println(msg);
}
});
}
})
// 6. ç»å®çå¬ç«¯å£
.bind(8080);
}
}
```
* Client.java
```java
public class HelloClient {
public static void main(String[] args) throws InterruptedException {
// 1. å建å¯å¨å¨ç±»
new Bootstrap()
// 2. æ·»å EventLoop
.group(new NioEventLoopGroup())
//.option()ï¼ç» SocketChannel é
ç½®åæ°
// 3. 鿩客æ·ç«¯ channel å®ç°
.channel(NioSocketChannel.class)
// 4. æ·»å å¤çå¨
.handler(new ChannelInitializer() {
// 4.1 è¿æ¥å»ºç«å被è°ç¨
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// å° Hello World 转为 ByteBuf
ch.pipeline().addLast(new StringEncoder());
}
})
// 5. è¿æ¥å°æå¡å¨ï¼ç¶åè°ç¨ 4.1
.connect(new InetSocketAddress("127.0.0.1",8080))
// 6. é»å¡æ¹æ³ï¼ç´å°è¿æ¥å»ºç«
.sync()
// 7. ä»£è¡¨è¿æ¥å¯¹è±¡
.channel()
// 8. åæå¡å¨åéæ°æ®
.writeAndFlush("Hello World");
}
}
```
åèè§é¢ï¼https://www.bilibili.com/video/BV1py4y1E7oA
****
## ç»ä»¶ä»ç»
### EventLoop
#### åºæ¬ä»ç»
äºä»¶å¾ªç¯å¯¹è±¡ EventLoopï¼**æ¬è´¨æ¯ä¸ä¸ªåçº¿ç¨æ§è¡å¨åæ¶ç»´æ¤äºä¸ä¸ª Selector**ï¼æ run æ¹æ³å¤ç Channel 䏿ºæºä¸æç IO äºä»¶
äºä»¶å¾ªç¯ç» EventLoopGroup æ¯ä¸ç» EventLoopï¼Channel ä¼è°ç¨ Boss EventLoopGroup ç register æ¹æ³æ¥ç»å®å
¶ä¸ä¸ä¸ª Worker ç EventLoopï¼åç»è¿ä¸ª Channel ä¸ç IO äºä»¶é½ç±æ¤ EventLoop æ¥å¤çï¼ä¿è¯äºäºä»¶å¤çæ¶ç线ç¨å®å
¨
EventLoopGroup ç±» APIï¼
* `EventLoop next()`ï¼è·åéåä¸ä¸ä¸ä¸ª EventLoopï¼EventLoopGroup å®ç°äº Iterable æ¥å£æä¾éå EventLoop çè½å
* `Future> shutdownGracefully()`ï¼ä¼é
å
³éçæ¹æ³ï¼ä¼é¦å
忢 EventLoopGroup å°å
³éç¶æä»èæç»æ°çä»»å¡çå å
¥ï¼ç¶åå¨ä»»å¡éåçä»»å¡é½å¤ç宿åï¼åæ¢çº¿ç¨çè¿è¡ï¼ä»èç¡®ä¿æ´ä½åºç¨æ¯å¨æ£å¸¸æåºçç¶æä¸éåºç
* ` Future submit(Callable task)`ï¼æäº¤ä»»å¡
* `ScheduledFuture> scheduleWithFixedDelay`ï¼æäº¤å®æ¶ä»»å¡
***
#### ä»»å¡ä¼ é
æè¦è°ç¨ç代ç å°è£
为ä¸ä¸ªä»»å¡å¯¹è±¡ï¼ç±ä¸ä¸ä¸ª handler ççº¿ç¨æ¥è°ç¨
```java
public class EventLoopServer {
public static void main(String[] args) {
EventLoopGroup group = new DefaultEventLoopGroup();
new ServerBootstrap()
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast("handler1", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
log.debug(buf.toString(Charset.defaultCharset()));
ctx.fireChannelRead(msg); // è®©æ¶æ¯ãä¼ éãç»ä¸ä¸ä¸ª handler
}
}).addLast(group, "handler2", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
log.debug(buf.toString(Charset.defaultCharset()));
}
});
}
})
.bind(8080);
}
}
```
æºç åæï¼
```java
public ChannelHandlerContext fireChannelRead(final Object msg) {
invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
return this;
}
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
// ä¸ä¸ä¸ª handler çäºä»¶å¾ªç¯æ¯å¦ä¸å½åçäºä»¶å¾ªç¯æ¯åä¸ä¸ªçº¿ç¨
if (executor.inEventLoop()) {
// æ¯ï¼ç´æ¥è°ç¨
next.invokeChannelRead(m);
} else {
// 䏿¯ï¼å°è¦æ§è¡ç代ç ä½ä¸ºä»»å¡æäº¤ç»ä¸ä¸ä¸ª handler å¤ç
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}
```
****
### Channel
#### è¿æ¥æä½
Channel ç±» APIï¼
* `ChannelFuture close()`ï¼å
³ééé
* `ChannelPipeline pipeline()`ï¼æ·»å å¤çå¨
* `ChannelFuture write(Object msg)`ï¼æ°æ®åå
¥ç¼å²åº
* `ChannelFuture writeAndFlush(Object msg)`ï¼æ°æ®åå
¥ç¼å²åºå¹¶ä¸å·åº
ChannelFuture ç±» APIï¼
* `ChannelFuture sync()`ï¼åæ¥é»å¡çå¾
è¿æ¥æå
* `ChannelFuture addListener(GenericFutureListener listener)`ï¼å¼æ¥çå¾
代ç å®ç°ï¼
* connect æ¹æ³æ¯å¼æ¥çï¼ä¸çè¿æ¥å»ºç«å®æå°±è¿åï¼å æ¤ channelFuture 对象ä¸ä¸è½ç«å»è·å¾å°æ£ç¡®ç Channel 对象ï¼éè¦çå¾
* è¿æ¥æªå»ºç« channel æå°ä¸º `[id: 0x2e1884dd]`ï¼å»ºç«æåæå°ä¸º `[id: 0x2e1884dd, L:/127.0.0.1:57191 - R:/127.0.0.1:8080]`
```java
public class ChannelClient {
public static void main(String[] args) throws InterruptedException {
ChannelFuture channelFuture = new Bootstrap()
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
})
// 1. è¿æ¥æå¡å¨ï¼ã弿¥éé»å¡ãï¼main è°ç¨ connect æ¹æ³ï¼çæ£æ§è¡è¿æ¥çæ¯ nio 线ç¨
.connect(new InetSocketAddress("127.0.0.1", 8080));
// 2.1 ä½¿ç¨ sync æ¹æ³ã忥ãå¤çç»æï¼é»å¡å½å线ç¨ï¼ç´å° nio 线ç¨è¿æ¥å»ºç«å®æ¯
channelFuture.sync();
Channel channel = channelFuture.channel();
System.out.println(channel); // ãæå°ã
// åæå¡å¨åéæ°æ®
channel.writeAndFlush("hello world");
**************************************************************************************äºéä¸
// 2.2 ä½¿ç¨ addListener æ¹æ³ã弿¥ãå¤çç»æ
channelFuture.addListener(new ChannelFutureListener() {
@Override
// nio 线ç¨è¿æ¥å»ºç«å¥½ä»¥åï¼åè°è¯¥æ¹æ³
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
Channel channel = future.channel();
channel.writeAndFlush("hello, world");
} else {
// 建ç«å¤±è´¥ï¼éè¦å
³é
future.channel().close();
}
}
});
}
}
```
***
#### å
³éæä½
å
³é EventLoopGroup çè¿è¡ï¼åä¸ºåæ¥å
³éå弿¥å
³é
```java
public class CloseFutureClient {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
ChannelFuture channelFuture = new Bootstrap()
// ....
.connect(new InetSocketAddress("127.0.0.1", 8080));
Channel channel = channelFuture.sync().channel();
// åéæ°æ®
new Thread(() -> {
Scanner sc = new Scanner(System.in);
while (true) {
String line = sc.nextLine();
if (line.equals("q")) {
channel.close();
break;
}
channel.writeAndFlush(line);
}
}, "input").start();
// è·å CloseFuture 对象
ChannelFuture closeFuture = channel.closeFuture();
// 1. 忥å¤çå
³é
System.out.println("waiting close...");
closeFuture.sync();
System.out.println("å¤çå
³éåçæä½");
****************************************************
// 2. 弿¥å¤çå
³é
closeFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
System.out.println("å¤çå
³éåçæä½");
group.shutdownGracefully();
}
});
}
}
```
****
### Future
#### åºæ¬ä»ç»
Netty ä¸ç Future ä¸ JDK ä¸ç Future ååï¼ä½æ¯åè½çå®ç°ä¸å
```java
package io.netty.util.concurrent;
public interface Future extends java.util.concurrent.Future
```
Future ç±» APIï¼
* `V get()`ï¼é»å¡çå¾
è·å任塿§è¡ç»æ
* `V getNow()`ï¼éé»å¡è·åä»»å¡ç»æï¼è¿æªäº§çç»ææ¶è¿å null
* `Throwable cause()`ï¼éé»å¡è·å失败信æ¯ï¼å¦ææ²¡æå¤±è´¥ï¼è¿å null
* `Future sync()`ï¼çå¾
ä»»å¡ç»æï¼å¦æä»»å¡å¤±è´¥ï¼æåºå¼å¸¸
* `boolean cancel(boolean mayInterruptIfRunning)`ï¼åæ¶ä»»å¡
* `Future addListener(GenericFutureListener listener)`ï¼æ·»å åè°ï¼å¼æ¥æ¥æ¶ç»æ
* `boolean isSuccess()`ï¼å¤æä»»å¡æ¯å¦æå
* `boolean isCancellable()`ï¼å¤æä»»å¡æ¯å¦åæ¶
```java
public class NettyFutureDemo {
public static void main(String[] args) throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup();
EventLoop eventLoop = group.next();
Future future = eventLoop.submit(new Callable() {
@Override
public Integer call() throws Exception {
System.out.println("æ§è¡è®¡ç®");
Thread.sleep(1000);
return 70;
}
});
future.getNow();
System.out.println(new Date() + "çå¾
ç»æ");
System.out.println(new Date() + "" + future.get());
}
}
```
****
#### æ©å±åç±»
Promise ç±»æ¯ Future çåç±»ï¼å¯ä»¥è±ç¦»ä»»å¡ç¬ç«åå¨ï¼ä½ä¸ºä¸¤ä¸ªçº¿ç¨é´ä¼ éç»æç容å¨
```java
public interface Promise extends Future
```
Promise ç±» APIï¼
* `Promise setSuccess(V result)`ï¼è®¾ç½®æåç»æ
* `Promise setFailure(Throwable cause)`ï¼è®¾ç½®å¤±è´¥ç»æ
```java
public class NettyPromiseDemo {
public static void main(String[] args) throws Exception {
// 1. åå¤ EventLoop 对象
EventLoop eventLoop = new NioEventLoopGroup().next();
// 2. 主å¨å建 promise
DefaultPromise promise = new DefaultPromise<>(eventLoop);
// 3. ä»»æä¸ä¸ªçº¿ç¨æ§è¡è®¡ç®ï¼è®¡ç®å®æ¯åå promise å¡«å
ç»æ
new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
promise.setSuccess(200);
}).start();
// 4. æ¥åç»æç线ç¨
System.out.println(new Date() + "çå¾
ç»æ");
System.out.println(new Date() + "" + promise.get());
}
}
```
****
### Pipeline
ChannelHandler ç¨æ¥å¤ç Channel ä¸çåç§äºä»¶ï¼å为å
¥ç«åºç«ä¸¤ç§ï¼ææ ChannelHandler è¿æ¥æååé¾è¡¨å°±æ¯ Pipeline
* å
¥ç«å¤çå¨éå¸¸æ¯ ChannelInboundHandlerAdapter çåç±»ï¼ä¸»è¦ç¨æ¥è¯»å客æ·ç«¯æ°æ®ï¼ååç»æ
* åºç«å¤çå¨éå¸¸æ¯ ChannelOutboundHandlerAdapter çåç±»ï¼ä¸»è¦å¯¹ååç»æè¿è¡å å·¥ï¼å
¥ç«ååºç«æ¯å¯¹äºæå¡ç«¯æ¥è¯´çï¼
```java
public static void main(String[] args) {
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// 1. éè¿ channel æ¿å° pipeline
ChannelPipeline pipeline = ch.pipeline();
// 2. æ·»å å¤çå¨ head -> h1 -> h2 -> h3 -> h4 -> tail
pipeline.addLast("h1", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.debug("1");
ByteBuf buf = (ByteBuf) msg;
String s = buf.toString(Charset.defaultCharset());
// å°æ°æ®ä¼ éç»ä¸ä¸ä¸ªãå
¥ç«ãhandlerï¼å¦æä¸è°ç¨è¯¥æ¹æ³åé¾ä¼æå¼
super.channelRead(ctx, s);
}
});
pipeline.addLast("h2", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.debug("2");
// ä»ãå°¾é¨å¼å§åå触åãåºç«å¤çå¨
ch.writeAndFlush(ctx.alloc().buffer().writeBytes("server".getBytes()));
// è¯¥æ¹æ³ä¼è®©ç®¡éä»ãå½å handler ååã寻æ¾åºç«å¤çå¨
// ctx.writeAndFlush();
}
});
pipeline.addLast("h3", new ChannelOutboundHandlerAdapter() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.debug("3");
super.write(ctx, msg, promise);
}
});
pipeline.addLast("h4", new ChannelOutboundHandlerAdapter() {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.debug("4");
super.write(ctx, msg, promise);
}
});
}
})
.bind(8080);
}
```
æå¡å¨ç«¯ä¾æ¬¡æå°ï¼1 2 4 3 ï¼æä»¥**å
¥ç«æ¯æç
§ addLast çé¡ºåºæ§è¡çï¼åºç«æ¯æç
§ addLast çéåºæ§è¡**
ä¸ä¸ª Channel å
å«äºä¸ä¸ª ChannelPipelineï¼è ChannelPipeline ä¸åç»´æ¤äºä¸ä¸ªç± ChannelHandlerContext ç»æçååé¾è¡¨ï¼å¹¶ä¸æ¯ä¸ª ChannelHandlerContext ä¸å
³èçä¸ä¸ª ChannelHandler
å
¥ç«äºä»¶ååºç«äºä»¶å¨ä¸ä¸ªååé¾è¡¨ä¸ï¼ä¸¤ç§ç±»åç handler äºä¸å¹²æ°ï¼
* å
¥ç«äºä»¶ä¼ä»é¾è¡¨ head å¾åä¼ éå°æåä¸ä¸ªå
¥ç«ç handler
* åºç«äºä»¶ä¼ä»é¾è¡¨ tail å¾åä¼ éå°æåä¸ä¸ªåºç«ç handler

****
### ByteBuf
#### åºæ¬ä»ç»
ByteBuf æ¯å¯¹åèæ°æ®çå°è£
ï¼ä¼ç¹ï¼
* æ± åï¼å¯ä»¥éç¨æ± ä¸ ByteBuf å®ä¾ï¼æ´è约å
åï¼åå°å
åæº¢åºçå¯è½
* 读åæéå离ï¼ä¸éè¦å ByteBuffer 䏿 ·åæ¢è¯»å模å¼
* å¯ä»¥èªå¨æ©å®¹
* æ¯æé¾å¼è°ç¨ï¼ä½¿ç¨æ´æµç
* é¶æ·è´ææ³ï¼ä¾å¦ sliceãduplicateãCompositeByteBuf
****
#### åå»ºæ¹æ³
å建æ¹å¼
* `ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(10)`ï¼å建äºä¸ä¸ªé»è®¤ç ByteBufï¼åå§å®¹éæ¯ 10
```java
public ByteBuf buffer() {
if (directByDefault) {
return directBuffer();
}
return heapBuffer();
}
```
* `ByteBuf buffer = ByteBufAllocator.DEFAULT.heapBuffer(10)`ï¼åå»ºæ± ååºäºå ç ByteBuf
* `ByteBuf buffer = ByteBufAllocator.DEFAULT.directBuffer(10)`ï¼åå»ºæ± ååºäºç´æ¥å
åç ByteBuf
* **æ¨è**çå建æ¹å¼ï¼å¨æ·»å å¤çå¨çæ¹æ³ä¸
```java
pipeline.addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = ctx.alloc().buffer();
}
});
```
ç´æ¥å
å对æ¯å å
åï¼
* ç´æ¥å
åå建å鿝ç代价æè´µï¼ä½è¯»åæ§è½é«ï¼å°ä¸æ¬¡å
åå¤å¶ï¼ï¼éåé
åæ± ååè½ä¸èµ·ç¨
* ç´æ¥å
å对 GC ååå°ï¼å 为è¿é¨åå
åä¸å JVM åå¾åæ¶ç管çï¼ä½ä¹è¦æ³¨æåæ¶ä¸»å¨éæ¾
æ± åçæä¹å¨äºå¯ä»¥**éç¨ ByteBuf**ï¼é«å¹¶åæ¶æ± ååè½æ´è约å
åï¼åå°å
åæº¢åºçå¯è½ï¼ä¸éæ± å对æ¯ï¼
* éæ± åï¼æ¯æ¬¡é½è¦å建æ°ç ByteBuf å®ä¾ï¼è¿ä¸ªæä½å¯¹ç´æ¥å
å代价æè´µï¼å å
åä¼å¢å GC åå
* æ± åï¼å¯ä»¥éç¨æ± ä¸ ByteBuf å®ä¾ï¼å¹¶ä¸éç¨äºä¸ jemalloc 类似çå
ååé
ç®æ³æååé
æç
æ± ååè½çå¼å¯ï¼å¯ä»¥éè¿ä¸é¢çç³»ç»ç¯å¢åéæ¥è®¾ç½®ï¼
```sh
-Dio.netty.allocator.type={unpooled|pooled} # VM åæ°
```
* 4.1 以åï¼é Android å¹³å°é»è®¤å¯ç¨æ± åå®ç°ï¼Android å¹³å°å¯ç¨éæ± åå®ç°
* 4.1 ä¹åï¼æ± ååè½è¿ä¸æçï¼é»è®¤æ¯éæ± åå®ç°
****
#### 读åæä½
ByteBuf ç±åé¨åç»æï¼æå¼å§è¯»åæéï¼**åæé**ï¼é½å¨ 0 ä½ç½®

åå
¥æ¹æ³ï¼
| æ¹æ³å | 说æ | 夿³¨ |
| ------------------------------------------------ | ---------------------- | ------------------------------------------- |
| writeBoolean(boolean value) | åå
¥ boolean å¼ | ç¨ä¸åè 01\|00 代表 true\|false |
| writeByte(int value) | åå
¥ byte å¼ | |
| writeInt(int value) | åå
¥ int å¼ | Big Endianï¼å³ 0x250ï¼åå
¥å 00 00 02 50 |
| writeIntLE(int value) | åå
¥ int å¼ | Little Endianï¼å³ 0x250ï¼åå
¥å 50 02 00 00 |
| writeBytes(ByteBuf src) | åå
¥ ByteBuf | |
| writeBytes(byte[] src) | åå
¥ byte[] | |
| writeBytes(ByteBuffer src) | åå
¥ NIO ç ByteBuffer | |
| int writeCharSequence(CharSequence s, Charset c) | åå
¥å符串 | |
* è¿äºæ¹æ³çæªææè¿åå¼çï¼å
¶è¿åå¼é½æ¯ ByteBufï¼æå³çå¯ä»¥é¾å¼è°ç¨
* åå
¥å ä½åæéåç§»å ä½ï¼æåå¯ä»¥åå
¥çä½ç½®
* ç½ç»ä¼ è¾ï¼é»è®¤ä¹ æ¯æ¯ Big Endian
æ©å®¹ï¼åå
¥æ°æ®æ¶ï¼å®¹éä¸å¤äºï¼åå§å®¹éæ¯ 10ï¼ï¼è¿æ¶ä¼å¼å**æ©å®¹**
* 妿åå
¥åæ°æ®å¤§å°æªè¶
è¿ 512ï¼åéæ©ä¸ä¸ä¸ª 16 çæ´æ°åï¼ä¾å¦åå
¥å大å°ä¸º 12 ï¼åæ©å®¹å capacity æ¯ 16
* 妿åå
¥åæ°æ®å¤§å°è¶
è¿ 512ï¼åéæ©ä¸ä¸ä¸ª 2^nï¼ä¾å¦åå
¥å大å°ä¸º 513ï¼åæ©å®¹å capacity æ¯ 2^10 = 1024ï¼2^9=512 ä¸å¤ï¼
* æ©å®¹ä¸è½è¶
è¿ max capacity 伿¥é
è¯»åæ¹æ³ï¼
* `byte readByte()`ï¼è¯»åä¸ä¸ªåèï¼è¯»æéåç§»
* `byte getByte(int index)`ï¼è¯»åæå®ç´¢å¼ä½ç½®çåèï¼è¯»æéä¸å¨
* `ByteBuf markReaderIndex()`ï¼æ è®°è¯»æ°æ®çä½ç½®
* `ByteBuf resetReaderIndex()`ï¼éç½®å°æ è®°ä½ç½®ï¼å¯ä»¥éå¤è¯»åæ è®°ä½ç½®ååçæ°æ®
****
#### å
åéæ¾
Netty ä¸ä¸ç§å
åçåæ¶ï¼
* UnpooledHeapByteBuf 使ç¨çæ¯ JVM å
åï¼åªéç GC åæ¶å
å
* UnpooledDirectByteBuf 使ç¨çå°±æ¯ç´æ¥å
åäºï¼éè¦ç¹æ®çæ¹æ³æ¥åæ¶å
å
* PooledByteBuf åå类使ç¨äºæ± åæºå¶ï¼éè¦æ´å¤æçè§åæ¥åæ¶å
å
Netty éç¨äºå¼ç¨è®¡æ°æ³æ¥æ§å¶åæ¶å
åï¼æ¯ä¸ª ByteBuf é½å®ç°äº ReferenceCounted æ¥å£ï¼åæ¶çè§åï¼
* æ¯ä¸ª ByteBuf 对象çåå§è®¡æ°ä¸º 1
* è°ç¨ release æ¹æ³è®¡æ°å 1ï¼å¦æè®¡æ°ä¸º 0ï¼ByteBuf å
åè¢«åæ¶
* è°ç¨ retain æ¹æ³è®¡æ°å 1ï¼è¡¨ç¤ºè°ç¨è
没ç¨å®ä¹åï¼å
¶å® handler å³ä½¿è°ç¨äº release ä¹ä¸ä¼é æåæ¶
* å½è®¡æ°ä¸º 0 æ¶ï¼åºå±å
åä¼è¢«åæ¶ï¼è¿æ¶å³ä½¿ ByteBuf 对象è¿å¨ï¼å
¶åä¸ªæ¹æ³åæ æ³æ£å¸¸ä½¿ç¨
```java
ByteBuf buf = .ByteBufAllocator.DEFAULT.buffer(10)
try {
// é»è¾å¤ç
} finally {
buf.release();
}
```
Pipeline çåå¨ï¼éè¦å° ByteBuf ä¼ éç»ä¸ä¸ä¸ª ChannelHandlerï¼å¦æå¨ finally ä¸ release äºï¼å°±å¤±å»äºä¼ éæ§ï¼å¤çè§åï¼
* å建 ByteBuf æ¾å
¥ Pipeline
* å
¥ç« ByteBuf å¤çåå
* 对åå§ ByteBuf ä¸åå¤çï¼è°ç¨ ctx.fireChannelRead(msg) ååä¼ éï¼è¿æ¶æ é¡» releaseï¼åä¹ä¸ä¼ ééè¦
* å°åå§ ByteBuf 转æ¢ä¸ºå
¶å®ç±»åç Java 对象ï¼è¿æ¶ ByteBuf 就没ç¨äºï¼æ¤æ¶å¿
é¡» release
* 妿åºç°å¼å¸¸ï¼ByteBuf 没ææåä¼ éå°ä¸ä¸ä¸ª ChannelHandlerï¼å¿
é¡» release
* åè®¾æ¶æ¯ä¸ç´ååä¼ ï¼é£ä¹ TailContext ä¼è´è´£éæ¾æªå¤çæ¶æ¯ï¼åå§ç ByteBufï¼
```java
// io.netty.channel.DefaultChannelPipeline#onUnhandledInboundMessage(java.lang.Object)
protected void onUnhandledInboundMessage(Object msg) {
try {
logger.debug();
} finally {
ReferenceCountUtil.release(msg);
}
}
// io.netty.util.ReferenceCountUtil#release(java.lang.Object)
public static boolean release(Object msg) {
if (msg instanceof ReferenceCounted) {
return ((ReferenceCounted) msg).release();
}
return false;
}
```
* åºç« ByteBuf å¤çåå
* åºç«æ¶æ¯æç»é½ä¼è½¬ä¸º ByteBuf è¾åºï¼ä¸ç´ååä¼ ï¼ç± HeadContext flush å release
* ä¸ç¡®å® ByteBuf 被å¼ç¨äºå¤å°æ¬¡ï¼ä½åå¿
须彻åºéæ¾ï¼å¯ä»¥å¾ªç¯è°ç¨ release ç´å°è¿å true
****
#### æ·è´æä½
é¶æ·è´æ¹æ³ï¼
* `ByteBuf slice(int index, int length)`ï¼å¯¹åå§ ByteBuf è¿è¡åçæå¤ä¸ª ByteBufï¼åçåç ByteBuf 并没æåçå
åå¤å¶ï¼**å
±ç¨åå§ ByteBuf çå
å**ï¼åçåç ByteBuf ç»´æ¤ç¬ç«ç readï¼write æé
```java
public static void main(String[] args) {
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(10);
buf.writeBytes(new byte[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'});
// å¨åçè¿ç¨ä¸å¹¶æ²¡æåçæ°æ®å¤å¶
ByteBuf f1 = buf.slice(0, 5);
f1.retain();
ByteBuf f2 = buf.slice(5, 5);
f2.retain();
// 对 f1 è¿è¡ç¸å
³çæä½ä¹ä¼ä½ç°å¨ buf ä¸
}
```
* `ByteBuf duplicate()`ï¼æªååå§ ByteBuf ææå
容ï¼å¹¶ä¸æ²¡æ max capacity çéå¶ï¼ä¹æ¯ä¸åå§ ByteBuf 使ç¨åä¸ååºå±å
åï¼åªæ¯è¯»åæéæ¯ç¬ç«ç
* `CompositeByteBuf addComponents(boolean increaseWriterIndex, ByteBuf... buffers)`ï¼åå¹¶å¤ä¸ª ByteBuf
```java
public static void main(String[] args) {
ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();
buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer();
buf1.writeBytes(new byte[]{6, 7, 8, 9, 10});
CompositeByteBuf buf = ByteBufAllocator.DEFAULT.compositeBuffer();
// true 表示å¢å æ°ç ByteBuf èªå¨éå¢ write index, å¦å write index ä¼å§ç»ä¸º 0
buf.addComponents(true, buf1, buf2);
}
```
CompositeByteBuf æ¯ä¸ä¸ªç»åç ByteBufï¼å
é¨ç»´æ¤äºä¸ä¸ª Component æ°ç»ï¼æ¯ä¸ª Component 管çä¸ä¸ª ByteBufï¼è®°å½äºè¿ä¸ª ByteBuf ç¸å¯¹äºæ´ä½åç§»éçä¿¡æ¯ï¼ä»£è¡¨çæ´ä½ä¸æä¸æ®µçæ°æ®
* ä¼ç¹ï¼å¯¹å¤æ¯ä¸ä¸ªèæè§å¾ï¼ç»åè¿äº ByteBuf ä¸ä¼äº§çå
åå¤å¶
* 缺ç¹ï¼å¤æäºå¾å¤ï¼å¤æ¬¡æä½ä¼å¸¦æ¥æ§è½çæè
æ·±æ·è´ï¼
* `ByteBuf copy()`ï¼å°åºå±å
åæ°æ®è¿è¡æ·±æ·è´ï¼å æ¤æ 论读åï¼é½ä¸åå§ ByteBuf æ å
³
æ± åç¸å
³ï¼
* Unpooled æ¯ä¸ä¸ªå·¥å
·ç±»ï¼æä¾äºéæ± åç ByteBuf å建ãç»åãå¤å¶çæä½
```java
ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer(5);
buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer(5);
buf2.writeBytes(new byte[]{6, 7, 8, 9, 10});
// å½å
è£
ByteBuf 个æ°è¶
è¿ä¸ä¸ªæ¶, åºå±ä½¿ç¨äº CompositeByteBufï¼é¶æ·è´ææ³
ByteBuf buf = Unpooled.wrappedBuffer(buf1, buf2);
```
****
## ç²å
åå
### ç°è±¡æ¼ç¤º
å¨ TCP ä¼ è¾ä¸ï¼å®¢æ·ç«¯åéæ¶æ¯æ¶ï¼å®é
䏿¯å°æ°æ®åå
¥ TCP çç¼åï¼æ¤æ¶æ°æ®ç大å°åç¼åç大å°å°±ä¼é æç²å
ååå
* 彿°æ®è¶
è¿ TCP ç¼å容鿶ï¼å°±ä¼è¢«æåæå¤ä¸ªå
ï¼éè¿ Socket 夿¬¡åéå°æå¡ç«¯ï¼æå¡ç«¯æ¯æ¬¡ä»ç¼åä¸åæ°æ®ï¼äº§çåå
é®é¢
* 彿°æ®å°äº TCP ç¼å容鿶ï¼ç¼åä¸å¯ä»¥åæ¾å¤ä¸ªå
ï¼å®¢æ·ç«¯åæå¡ç«¯ä¸æ¬¡éä¿¡å°±å¯è½ä¼ éå¤ä¸ªå
ï¼è¿æ¶åæå¡ç«¯å°±å¯è½ä¸æ¬¡è¯»åå¤ä¸ªå
ï¼äº§çç²å
çé®é¢
ä»£ç æ¼ç¤ºï¼
* 客æ·ç«¯ä»£ç ï¼
```java
public class HelloWorldClient {
public static void main(String[] args) {
send();
}
private static void send() {
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(worker);
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
// ãå¨è¿æ¥ channel å»ºç«æååï¼ä¼è§¦å active æ¹æ³ã
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// åéå
å®¹éæºçæ°æ®å
Random r = new Random();
char c = '0';
ByteBuf buf = ctx.alloc().buffer();
for (int i = 0; i < 10; i++) {
byte[] bytes = new byte[10];
for (int j = 0; j < r.nextInt(9) + 1; j++) {
bytes[j] = (byte) c;
}
c++;
buf.writeBytes(bytes);
}
ctx.writeAndFlush(buf);
}
});
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("client error", e);
} finally {
worker.shutdownGracefully();
}
}
}
```
* æå¡å¨ä»£ç ï¼
```java
public class HelloWorldServer {
public static void main(String[] args) {
NioEventLoopGroup boss = new NioEventLoopGroup(1);
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.channel(NioServerSocketChannel.class);
// è°æ´ç³»ç»çæ¥åç¼å²åºãæ»å¨çªå£ã
//serverBootstrap.option(ChannelOption.SO_RCVBUF, 10);
// è°æ´ netty çæ¥åç¼å²åºï¼ByteBufï¼
//serverBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR,
// new AdaptiveRecvByteBufAllocator(16, 16, 16));
serverBootstrap.group(boss, worker);
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// ãè¿éå¯ä»¥æ·»å è§£ç å¨ã
// LoggingHandler ç¨æ¥æå°æ¶æ¯
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8080);
channelFuture.sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("server error", e);
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
log.debug("stop");
}
}
}
```
* ç²å
ææå±ç¤ºï¼
```java
09:57:27.140 [nioEventLoopGroup-3-1] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0xddbaaef6, L:/127.0.0.1:8080 - R:/127.0.0.1:8701] READ: 100B // è¯»äº 100 åèï¼åçç²å
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 30 30 30 30 30 00 00 00 00 00 31 00 00 00 00 00 |00000.....1.....|
|00000010| 00 00 00 00 32 32 32 32 00 00 00 00 00 00 33 00 |....2222......3.|
|00000020| 00 00 00 00 00 00 00 00 34 34 00 00 00 00 00 00 |........44......|
|00000030| 00 00 35 35 35 35 00 00 00 00 00 00 36 36 36 00 |..5555......666.|
|00000040| 00 00 00 00 00 00 37 37 37 37 00 00 00 00 00 00 |......7777......|
|00000050| 38 38 38 38 38 00 00 00 00 00 39 39 00 00 00 00 |88888.....99....|
|00000060| 00 00 00 00 |.... |
+--------+-------------------------------------------------+----------------+
```
è§£å³æ¹æ³ï¼éè¿è°æ´ç³»ç»çæ¥åç¼å²åºçæ»å¨çªå£å Netty çæ¥åç¼å²åºä¿è¯æ¯æ¡å
åªå«æä¸æ¡æ°æ®ï¼æ»å¨çªå£ç大å°ä»
å³å®äº Netty 读åç**æå°åä½**ï¼å®é
æ¯æ¬¡è¯»åçä¸è¬æ¯å®çæ´æ°å
***
### è§£å³æ¹æ¡
#### çè¿æ¥
åä¸ä¸ªå
建ç«ä¸æ¬¡è¿æ¥ï¼è¿æ ·è¿æ¥å»ºç«å°è¿æ¥æå¼ä¹é´å°±æ¯æ¶æ¯çè¾¹çï¼ç¼ºç¹å°±æ¯æçå¾ä½
客æ·ç«¯ä»£ç æ¹é ï¼
```java
public class HelloWorldClient {
public static void main(String[] args) {
// å 10 次åé
for (int i = 0; i < 10; i++) {
send();
}
}
}
```
****
#### åºå®é¿åº¦
æå¡å¨ç«¯å å
¥å®é¿è§£ç å¨ï¼æ¯ä¸æ¡æ¶æ¯éç¨åºå®é¿åº¦ã妿æ¯åå
æ¶æ¯ï¼ä¼ç¼ååå
æ¶æ¯å¹¶çå¾
ä¸ä¸ªå
å°è¾¾ä¹åè¿è¡æ¼å
åå¹¶ï¼ç´å°è¯»åä¸ä¸ªå®æ´çæ¶æ¯å
ï¼å¦ææ¯ç²å
æ¶æ¯ï¼ç©ºä½çä½ç½®ä¼è¿è¡è¡¥ 0ï¼ä¼æµªè´¹ç©ºé´
```java
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new FixedLengthFrameDecoder(10));
// LoggingHandler ç¨æ¥æå°æ¶æ¯
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
}
});
```
```java
10:29:06.522 [nioEventLoopGroup-3-1] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x38a70fbf, L:/127.0.0.1:8080 - R:/127.0.0.1:10144] READ: 10B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 31 31 00 00 00 00 00 00 00 00 |11........ |
+--------+-------------------------------------------------+----------------+
10:29:06.522 [nioEventLoopGroup-3-1] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0x38a70fbf, L:/127.0.0.1:8080 - R:/127.0.0.1:10144] READ: 10B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 32 32 32 32 32 32 00 00 00 00 |222222.... |
+--------+-------------------------------------------------+----------------+
```
****
#### åé符
æå¡ç«¯å å
¥è¡è§£ç å¨ï¼é»è®¤ä»¥ `\n` æ `\r\n` ä½ä¸ºåé符ï¼å¦æè¶
åºæå®é¿åº¦ä»æªåºç°åé符ï¼åæåºå¼å¸¸ï¼
```java
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new FixedLengthFrameDecoder(8));
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
}
});
```
客æ·ç«¯å¨æ¯æ¡æ¶æ¯ä¹åï¼å å
¥ `\n` åé符ï¼
```java
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Random r = new Random();
char c = 'a';
ByteBuf buffer = ctx.alloc().buffer();
for (int i = 0; i < 10; i++) {
for (int j = 1; j <= r.nextInt(16)+1; j++) {
buffer.writeByte((byte) c);
}
// 10 代表 '\n'
buffer.writeByte(10);
c++;
}
ctx.writeAndFlush(buffer);
}
```
****
#### é¢è®¾é¿åº¦
LengthFieldBasedFrameDecoder è§£ç å¨èªå®ä¹é¿åº¦è§£å³ TCP ç²å
é»å
é®é¢
```java
int maxFrameLength // æ°æ®æå¤§é¿åº¦
int lengthFieldOffset // é¿åº¦å段åç§»éï¼ä»ç¬¬å 个åèå¼å§æ¯å
容çé¿åº¦å段
int lengthFieldLength // é¿åº¦å段æ¬èº«çé¿åº¦
int lengthAdjustment // é¿åº¦å段为åºåï¼å 个åèåææ¯å
容
int initialBytesToStrip // ä»å¤´å¼å§å¥ç¦»å 个åèè§£ç åæ¾ç¤º
```
```java
lengthFieldOffset = 1 (= the length of HDR1)
lengthFieldLength = 2
lengthAdjustment = 1 (= the length of HDR2)
initialBytesToStrip = 3 (= the length of HDR1 + LEN)
BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)//è§£ç
+------+--------+------+----------------+ +------+----------------+
| HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
| 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
+------+--------+------+----------------+ +------+----------------+
```
代ç å®ç°ï¼
```java
public class LengthFieldDecoderDemo {
public static void main(String[] args) {
EmbeddedChannel channel = new EmbeddedChannel(
// int å 4 åèï¼çæ¬å·ä¸ä¸ªåè
new LengthFieldBasedFrameDecoder(1024, 0, 4, 1,5),
new LoggingHandler(LogLevel.DEBUG)
);
// 4 个åèçå
容é¿åº¦ï¼ å®é
å
容
ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
send(buffer, "Hello, world");
send(buffer, "Hi!");
// ååºç¼å
channel.writeInbound(buffer);
}
// åå
¥ç¼å
private static void send(ByteBuf buffer, String content) {
byte[] bytes = content.getBytes(); // å®é
å
容
int length = bytes.length; // å®é
å
容é¿åº¦
buffer.writeInt(length);
buffer.writeByte(1); // è¡¨ç¤ºçæ¬å·
buffer.writeBytes(bytes);
}
}
```
```java
10:49:59.344 [main] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0xembedded, L:embedded - R:embedded] READ: 12B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 |Hello, world |
+--------+-------------------------------------------------+----------------+
10:49:59.344 [main] DEBUG io.netty.handler.logging.LoggingHandler - [id: 0xembedded, L:embedded - R:embedded] READ: 3B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 48 69 21 |Hi! |
+--------+-------------------------------------------------+----------------+
```
****
### å议设计
#### HTTP
è®¿é® URLï¼http://localhost:8080/
```java
public class HttpDemo {
public static void main(String[] args) {
NioEventLoopGroup boss = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.group(boss, worker);
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
ch.pipeline().addLast(new HttpServerCodec());
// åªé对æä¸ç§ç±»åç请æ±å¤çï¼æ¤å¤é对 HttpRequest
ch.pipeline().addLast(new SimpleChannelInboundHandler() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) {
// è·å请æ±
log.debug(msg.uri());
// è¿åååº
DefaultFullHttpResponse response = new DefaultFullHttpResponse(
msg.protocolVersion(), HttpResponseStatus.OK);
byte[] bytes = "Hello, world!
".getBytes();
response.headers().setInt(CONTENT_LENGTH, bytes.length);
response.content().writeBytes(bytes);
// ååååº
ctx.writeAndFlush(response);
}
});
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error("n3.server error", e);
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
```
***
#### èªå®ä¹
å¤çå¨ä»£ç ï¼
```java
@Slf4j
public class MessageCodec extends ByteToMessageCodec {
// ç¼ç
@Override
public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
// 4 åèçéæ°
out.writeBytes(new byte[]{1, 2, 3, 4});
// 1 åèççæ¬,
out.writeByte(1);
// 1 åèçåºååæ¹å¼ jdk 0 , json 1
out.writeByte(0);
// 1 åèçæä»¤ç±»å
out.writeByte(msg.getMessageType());
// 4 个åè
out.writeInt(msg.getSequenceId());
// æ æä¹ï¼å¯¹é½å¡«å
, 1 åè
out.writeByte(0xff);
// è·åå
容çåèæ°ç»ï¼msg 对象åºåå
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(msg);
byte[] bytes = bos.toByteArray();
// é¿åº¦
out.writeInt(bytes.length);
// åå
¥å
容
out.writeBytes(bytes);
}
// è§£ç
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List