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
相关文章
相关标签/搜索