PHP 進階之路 - 後端多元化之快速切入 Java 開發

下面是我直播的文字版,直播地址: https://segmentfault.com/l/15...
代碼: https://github.com/zhoumengka...
整個項目咱們我又細分了6個版原本演進,但願更加便於你們對比學習。

誤解

我在收集你們是否願意學習 java 的時候,獲得了以下反饋:php

java == 太複雜
java == 各類亂七八糟的配置
java == 面向 ide 編程

其實咱們在學習的時候 java 的時候徹底不用接觸那些高大上的工具,也能夠儘可能減小各類配置文件,好比下面咱們只有個pom.xml配置文件。
還有的同窗說還學 java 幹嗎,不都應該去學 go 嗎?其實語言真的不重要,咱們須要掌握的是快速學習利用一門語言的學習方法,這也是本課的真正目的。html

入門不要拿着放大鏡去學

就像盲人摸象同樣,他要想弄清楚大象的真實面貌可能要摸好久,就比如咱們拿着放大鏡在學習 java 同樣,java 通過這麼多年的發展,能夠說很是龐大。若是咱們要知道大象長什麼樣,就應該放下手中的放大鏡,向後退遠點,反而可以很是清晰的看到它的全貌。學習一門新的語言也同樣,有不少不少網上的教程,很是的大而全,通常得系統的學習30~60小時以後才能正式的接觸項目開發。基礎很重要,可是學習了太多的基礎會讓你們失去學習的樂趣和自信心。不少知識點其實能夠項目以後再補。按需去學,反而是自我驅動着去學習的最佳方式。
圖片描述前端

好比 hashmap 的哈希分佈、哈希碰撞、動態擴容,這些都是咱們後期深刻提升須要理解的內容,初期,咱們只須要知道能拿 hashmap 作什麼就行。java

以實現本身熟悉的東西爲導向

好比咱們作 Web 後端 api 開發,首先是經常使用的循環/迭代、條件判斷、增刪改爲。那麼能不能快速用 java 實現一遍這些咱們用 php 作起來很是順手的事呢?
這樣有助於咱們快速提高自信心。mysql

使用類比的學習方法

PHP 裏如何實現,從新用 java 實現一遍就好了。nginx

最後深刻系統的學習

當本身實現了一些小 demo 再去參考別人的項目。若是一開始就直接看別人的項目,可能徹底不知作別人在幹嗎。好比別人用了ConcurrentHashMap,就再去思考爲何我用HashMap他卻用ConcurrentHashMap,帶着問題,帶着思考去看開源代碼。git

完成了一些簡單的項目了以後就能夠再回過頭來系統的學習了。這時候就會有不同的收穫。github

最後就是當項目須要調優,性能提高的時候,再各個擊破,深刻學習,更有針對性,更有目標性。web

實戰開始

咱們用 netty 來提供高性能的 web 服務服務。使用簡單方便(netty 並不簡單),不依賴其餘軟件。而後思考完成一個簡單的 web api 服務器須要哪些必不可少的組成部分。(其實在思考這的時候,你必需要要對作簡單的架構必須熟記於心)。redis

我簡單歸納了下:

  1. java 基礎數據類型(php 也有,不怕)
  2. java 集合框架(php 有數組,很強大)
  3. 初識 maven(php 有 composer)
  4. 反射 (框架路由等地方要用到,php 也有)
  5. 序列化(數據傳輸要用到,php 沒有複雜的數據結構要簡單 N 倍)
  6. jdbc (數據庫操做要用到,php 有 pdo)
  7. 大概認識泛型、註解等語法 (可選)
  8. 使用 netty 實戰開發一個 web api 服務(php 有 swoole)

Java 基本的數據結構、各類基本數據類型包裝類

圖片描述

Java - Collections Framework 高頻類舉例

圖片描述

HashSet 是一個沒有重複元素的集合。它是由HashMap實現的,不保證元素的順序,也就是說所說元素插入的順序與輸出的順序不一致。

這實際上是個人老朋友了,redis 裏常常用,好比我們能夠它來實現一個黑名單,這樣查找的速度就很是快,也不用去遠程查詢 redis 了,直接在當前內存中查詢。

ArrayList 基於數組來實現集合的功能,其內部維護了一個可變長的對象數組,集合內全部對象存儲於這個數組中,並實現該數組長度的動態伸縮。

這不就是咱們的 PHP 裏面經常使用的索引數組麼?

HashMap 以哈希表數據結構實現,查找對象時經過哈希函數計算其位置,它是爲快速查詢而設計的。特色就是快,非線程安全。

這不就是咱們的 PHP 裏面經常使用的關聯數組麼?

http://www.cnblogs.com/ITtang...
http://www.jianshu.com/p/b54f...
http://www.cnblogs.com/xiaoxi...

初識 maven

Maven的基本原理很簡單,採用遠程倉庫和本地倉庫以及一個核心的配置文件pom.xml,pom.xml中定義的jar文件從遠程倉庫下載到本地倉庫,各個項目使用同一個本地倉庫的jar,同一個版本的jar只需下載一次,並且避免每一個應用都去拷貝jar。

這和 php 的包管理工具 composer 很像,或者是 composer 是參考着 maven 而設計的。maven 的功能更強大,composer 須要每一個項目都要導入一遍,maven 卻像 git 同樣,有一個本地倉庫,第三方包也不會直接引用到項目中,而是在編譯的時候纔會引入(是否是很方便)。另外一方面,maven 不只僅是包管理工具,並且是一個項目管理工具,集成了編譯、打包、單元測試等功能。

下面是最簡單的一個演示,依賴了 netty 、junit 兩個包。而後使用maven-compiler-plugin指定了編譯時候的版本規則。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>mengkang.net</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

v1.0 構建 http web 服務器

我複製了 netty 官方的 demo 地址以下:

https://github.com/zhoumengkang/netty-http-demo/tree/v1.0

當咱們運行api.mengkang.net.netty.HttpServer.main方法,服務器就跑起來了,當在瀏覽器裏訪問 http://localhost:9009/ 就會返回Hello World

方法 用途
api.mengkang.net.netty.HttpServer#main 服務器啓動的入口
api.mengkang.net.netty.HttpServerInitializer#initChannel 初始化 Channel
api.mengkang.net.netty.HttpServerHandler#channelRead 進行網絡 I/O

這是第一步,netty 這裏就充當了一個 web server 的角色。而咱們就能夠直接在 netty 提供的接口的基礎上作編程,而不須要想 nginx + php-fpm 還須要一次反向代理,性能高了許多。(swoole 的方式就很像 netty 了)。

v2.0 實現控制器的訪問

具體需求:提供一個 api 能夠用戶指定用戶的信息
定義接口:

http://localhost:10000/users/{id}
http://localhost:10000/?method=user.get&id={id}

可能如今你們早已習慣了前者 restful 的 api 接口。
由於這裏須要一次路由的映射和 http method 的匹配,考慮到學習的成本呢,我沒有選擇這種方式。
咱們今天的目標是以最簡單有效的方式實現咱們的功能。
咱們首先從最簡單的方式來實現(其實沒有路由的 api 反而是最快的,畢竟須要作的判斷少嘛)。
後面你們有興趣能夠參考我寫的一個 restful api 的 demo netty-restful-server

具體代碼

https://github.com/zhoumengkang/netty-http-demo/tree/v2.0

這一版本中作一個過渡版本,暫時控制器還不解析過多的參數。只完成一個$_GET['method']參數的解析。
主要的任務是經過獲取的$_GET['method']去執行UserController裏面的get方法。

方法 用途
api.mengkang.net.RequestHandler#response HttpServerHandler 處接管網絡請求
api.mengkang.net.RequestHandler#invoke 執行反射調用
api.mengkang.net.api.UserController#get 模擬輸出一個用戶的信息
重點是反射的運用
Class<?> classname;
    Method methodName;
    Object result = null;

    classname = Class.forName("api.mengkang.net.api." + clazz + "Controller");
    Object inst = classname.newInstance();
    methodName = classname.getMethod(function);
    result = methodName.invoke(inst);

v3.0 解析請求參數

具體代碼

https://github.com/zhoumengkang/netty-http-demo/tree/v3.0
方法 用途
api.mengkang.net.Request 封裝一個通用 api 請求對象,包含客戶端請求的$_GET,$_POST,ip 等
api.mengkang.net.RequestHandler#requestFetch 把請求解析成 api.mengkang.net.Request 對象
api.mengkang.net.RequestHandler#invoke api.mengkang.net.Request 傳遞給 Controller

反射實例化對象使用了構造函數 ,這樣就把請求的對象Request實例傳到 Controller 中去了。Controller 中的方法就能取到$_GET,$_POST,以及相似 php://input 的數據了。

Class<?> classname;
Object   classObject;
Constructor constructor;
Method methodName;
Object result = null;

classname = Class.forName("api.mengkang.net.api." + clazz + "Controller");
constructor = classname.getConstructor(Request.class);
classObject = constructor.newInstance(request);
methodName = classname.getMethod(function);
result = methodName.invoke(classObject);

v3.1 完善返回體信息

具體代碼

https://github.com/zhoumengkang/netty-http-demo/tree/v3.1
用途
api.mengkang.net.Response 封裝一個通用 api 響應對象
api.mengkang.net.ErrorCode 錯誤代碼統一規範起來
api.mengkang.net.netty.HttpServerHandler http 頭信息 改成 json

這樣就更像一個正規的 api 服務了。

v4.0 構建 User 對象

增長 User 對象, 增長 UserModel 來處理 User 對象的返回, 完善了錯誤返回機制.

用途
api.mengkang.net.entity.User 描述用戶對象,用於user.get接口的數據返回
api.mengkang.net.model.UserModel UserController調用,簡單分層
api.mengkang.net.ErrorCode 完善了錯誤類型
api.mengkang.net.api.UserController 完善了錯誤類型的判斷,返回給前端錯誤更友好

v5.0 使用數據庫動態查詢

用途
api/mengkang/net/utils/mysql 新增本身封裝的簡單的數據鏈接池的操做工具
api.mengkang.net.dao.UserDao 作數據庫鏈接的查詢,返回給UserModel

中間引入三個包,來作數據庫的查詢和數據庫的鏈接池

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.18</version>
</dependency>
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>

最後整個項目結構以下

├── main
│   ├── java
│   │   └── api
│   │       └── mengkang
│   │           └── net
│   │               ├── Config.java
│   │               ├── ErrorCode.java
│   │               ├── Request.java
│   │               ├── RequestHandler.java
│   │               ├── Response.java
│   │               ├── api
│   │               │   ├── BaseController.java
│   │               │   └── UserController.java
│   │               ├── dao
│   │               │   └── UserDao.java
│   │               ├── entity
│   │               │   └── User.java
│   │               ├── model
│   │               │   └── UserModel.java
│   │               ├── netty
│   │               │   ├── HttpServer.java
│   │               │   ├── HttpServerHandler.java
│   │               │   └── HttpServerInitializer.java
│   │               └── utils
│   │                   └── mysql
│   │                       ├── DMLTypes.java
│   │                       ├── DbFiled.java
│   │                       ├── JdbcPool.java
│   │                       ├── MySelect.java
│   │                       └── Mysql.java
│   └── resources
│       ├── api.properties
│       ├── read.db.properties
│       └── write.db.properties
相關文章
相關標籤/搜索