作者: houlijiang

  • Linux查看网络流量

    作为一个非职业运维,不时需要查看Linux服务器上的网络流量状况。本文介绍几个常用的Linux查看网络流量命令,并简要介绍其用法。部分命令系统已经内置,某些命令则需要从软件仓库或者自行编译安装,本文以CentOS系统为例介绍软件安装方法。

    查看总流量

    ip

    ip 命令来自 iproute2util 包,是查看、配置网络/路由的工具。作为 ifconfig 的替代品,ip 命令功能更强大,用法更语义化。

    ip命令在大多数系统上都已经默认安装,也可通过 yum install -y iproute 安装。ip 的 “-s -h” 参数查看各网卡的总流量,下图是 ip -s -h link 的输出结果:

    ip命令输出结果

    nload

    nload 命令可以查看各个网络设备的当前网络速率,也会展示流经设备的总流量。

    nload 来自EPEL软件库,CentOS安装命令为:yum install -y epel-release && yum install -y nload。查看eth0网卡流量 nload eth0命令输出如下:

    nload查看网络流量

    PS:netstat -s 和 ifconfig -s 都可以查看收发的总包(netstat分协议给出),但不会给出字节数据。

    查看实时网速网速

    nload 命令可以输出当前网速,上面已经介绍过,本节不再赘述。

    dstat

    dstat 是一个用来替换vmstatiostatnetstatnfsstatifstat的全能系统信息统计工具,支持数据实时刷新,输出直观易懂。

    dstat 默认没有安装,安装命令为:yum install -y dstatdstat -tnf 1 10 输出接下来10秒内每秒的网络数据:

    dstat输出

    sar

    sar 是System Activity Report的缩写,是一款全面的Linux系统运行状态统计和性能分析工具,可从磁盘IO、CPU负载、内存使用等多个维度对系统活动进行报告。

    sar 命令来自 sysstat 包,可使用这个命令安装:yum install -y sysstatsar -n TCP 1 10可查看接下来10秒内的tcp数据:

    sar查看tcp数据

    查看连接/进程流量

    ss/netstat

    ss 和 netstat 是查看活动链接/监听端口的常用命令。ss 是 netstat 的替代,性能更好,建议使用。

    ss 是 iproute2util 包的一部分,因此在大多数系统上默认安装,也可通过yum install -y iproute安装。netstat 来自 net-tools 包,新版系统上需要自行安装:yum install -y net-tools

    下图是用ss查看tcp连接的输出:

    ss查看tcp连接

    iftop

    iftop 是一款实时流量监控工具,可以查看每个连接的实时速率。

    iftop 来自EPEL软件库,安装命令是:yum install -y epel-release && yum install -y iftopiftop -nN -i eth0实时查看eth0网卡的各个连接和网速:

    iftop查看实时网速

    nethogs

    nethogs 是为了查看单个进程流量而设计的工具,按照进程进行带宽分组。

    nethogs 来自EPEL软件库,安装命令是:yum install -y epel-release && yum install -y nethogsnethogs -d 2 eth0 每2秒刷新流经eth0网卡的进程流量信息:

    nethogs输出

    其他

    tcpdump可以用来抓包,保存的数据可以用wireshark打开和查看。

  • Linux下删除乱码或特殊字符文件

    今天遇到一个问题,一个文件名是“-MXV9.log”,直接用rm删除的时候就报错,如下:

    [localhost]rm -MXV9.log
    rm: illegal option -- M
    rm: illegal option -- X
    rm: illegal option -- V
    rm: illegal option -- 9
    rm: illegal option -- .
    rm: illegal option -- l
    rm: illegal option -- o
    rm: illegal option -- g
    Usage: rm [-Rfir] file ...
    

    通常对这类文件都可以使用引号括起来删除,但是这里带引号删除也一样报illegal option的错。

    找了一些资料后发现这种文件可以这样删除:先ls -i 查到文件的inode,然后用find命令删除

    [localhost]ls -ilrt
    
    100985 -rw-r--r--  1 tbcs      users            0 Apr 18 11:32 -MXV9.log
    

    最前面一列的100985就是文件的inode,在主机上执行如下命令即可删除文件

    [localhost]find ./ -inum 100985 -exec rm {} \;
    或者 
    
    [localhost]find ./ -inum 100985 -delete;

    所以大家以后遇到文件名为乱码或者带有特殊字符的文件需要删除的情况下,可以尝试使用这种方法。

  • TMS、WMS、OMS和FMS,分别指什么呢?

    海外仓系统主要有TMS、WMS、OMS、FMS等功能模块,那么这几个功能分别指的是什么意思呢?跟着易境通的小编一起来了解一下吧!

    TMS:是指运输管理系统,能够通过多种方法和其他相关的操作一起提高物流的管理能力,主要管理物流轨迹、车辆管理,司机管理等,通过接口的方式与WMS系统链接实现数据互传。

    WMS:是指仓库管理系统,一款标准化、智能化过程导向管理的仓库管理软件,它结合了众多知名企业的实际情况和管理经验,能够准确、高效地管理跟踪客户订单、采购订单、以及仓库的综合管理。

    OMS:是指订单管理系统,主要管理物流轨迹、车辆管理,司机管理等,通过接口的方式与WMS系统链接实现数据互传。

    FMS:是指财务管理系统,在海外仓中主要用于费用结算管理。

    对于海外仓企业来说,OMS、WMS、TMS、FMS功能模块都是海外仓运营管理的信息化手段,可以单独使用,也可以协同一起使用。

    易境通海外仓系统包含国内头程发货至海外尾程及退货换标的处理,由WMS操作管理、TMS头程管理、OMS订单管理、FMS财务管理、CRM客户管理、DMS数据管理等各大功能模块融会贯通,以敏锐的信息技术赋能海外仓业务。易境通海外仓系统可以更智能化、流程化的进行仓储管理。能够在短时间内记录商品从运输到入库再到出库的所有信息,助力海外仓企业降本增效。

  • git重命名tag标签

    Git重命名tag标签教程

    在 git 中,我们要重命名一个 tag 标签,我们可以使用 git tag 命令。

    git重命名tag标签详解

    语法

    git tag newTag oldTag
    git tag -d oldTag 
    

    参数

    参数 描述
    newTag 新标签名。
    oldTag 重命名后的标签名。

    说明

    我们使用 git tag 将标签重命名后,我们还需要使用 git tag -d 命令,将旧标签删除,如果我们还需要将修改后的标签投送到远程,我们还需要使用如下命令:

    git push origin :refs/tags/oldTag
    git push --tags 
    

    push 命令中的冒号将标记从远程存储库。如果你不这样做,git 会在你的机器上创建旧的标签。最后,确保其他用户删除已删除的标签。请告诉他们(同事)运行以下命令:

    git pull --prune --tags 
    

    至此,重命名工作就完成了。

    Git重命名tag标签总结

    在 git 中,我们要重命名一个 tag 标签,我们可以使用 git tag 命令。

  • Linux tar.gz、tar、bz2、zip 等解压缩、压缩命令详解

    Linux tar.gz、tar、bz2、zip 等解压缩、压缩命令详解

    分类 编程技术

    Linux 常用的压缩与解压缩命令有:tar、gzip、gunzip、bzip2、bunzip2、compress 、uncompress、 zip、 unzip、rar、unrar 等。


    tar

    参数:

    • -z 用gzip指令处理备份文件
    • -v 显示执行过程
    • -f 指定备份文件
    • -c 建立备份文件
    • -t 列出备份文件的内容
    • -x 从备份文件中还原文件
    • -p 保留权限
    • –exclude 排除指定文件

    最常用的打包命令是 tar,使用 tar 程序打出来的包我们常称为 tar 包,tar 包文件的命令通常都是以 .tar 结尾的。生成 tar 包后,就可以用其它的程序来进行压缩了,所以首先就来讲讲 tar 命令的基本用法。

    tar 命令的选项有很多(用 man tar 可以查看到),但常用的就那么几个选项,下面来举例说明一下:

    # tar -cf all.tar *.jpg

    这条命令是将所有 .jpg 的文件打成一个名为 all.tar 的包。-c 是表示产生新的包,-f 指定包的文件名。

    # tar -rf all.tar *.gif

    这条命令是将所有 .gif 的文件增加到 all.tar 的包里面去,-r 是表示增加文件的意思。

    # tar -uf all.tar logo.gif

    这条命令是更新原来 tar 包 all.tar 中 logo.gif 文件,-u 是表示更新文件的意思。

    # tar -tf all.tar

    这条命令是列出 all.tar 包中所有文件,-t 是列出文件的意思。

    # tar -xf all.tar

    这条命令是解出 all.tar 包中所有文件,-x 是解开的意思。

    以上就是 tar 的最基本的用法。为了方便用户在打包解包的同时可以压缩或解压文件,tar 提供了一种特殊的功能。这就是 tar 可以在打包或解包的同时调用其它的压缩程序,比如调用 gzip、bzip2 等。

    1) tar调用

    gzip 是 GNU 组织开发的一个压缩程序,.gz 结尾的文件就是 gzip 压缩的结果。与 gzip 相对的解压程序是 gunzip。tar 中使用 -z 这个参数来调用gzip。下面来举例说明一下:

    # tar -czf all.tar.gz *.jpg

    这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 gzip 压缩,生成一个 gzip 压缩过的包,包名为 all.tar.gz。

    # tar -xzf all.tar.gz

    这条命令是将上面产生的包解开。

    2) tar 调用 bzip2

    bzip2 是一个压缩能力更强的压缩程序,.bz2 结尾的文件就是 bzip2 压缩的结果。

    与 bzip2 相对的解压程序是 bunzip2。tar 中使用 -j 这个参数来调用 gzip。下面来举例说明一下:

    # tar -cjf all.tar.bz2 *.jpg

    这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 bzip2 压缩,生成一个 bzip2 压缩过的包,包名为 all.tar.bz2

    # tar -xjf all.tar.bz2

    这条命令是将上面产生的包解开。

    3)tar 调用 compress

    compress 也是一个压缩程序,但是好象使用 compress 的人不如 gzip 和 bzip2 的人多。.Z 结尾的文件就是 bzip2 压缩的结果。与 compress 相对的解压程序是 uncompress。tar 中使用 -Z 这个参数来调用 compress。下面来举例说明一下:

    # tar -cZf all.tar.Z *.jpg

    这条命令是将所有 .jpg 的文件打成一个 tar 包,并且将其用 compress 压缩,生成一个 uncompress 压缩过的包,包名为 all.tar.Z。

    # tar -xZf all.tar.Z

    这条命令是将上面产生的包解开。

    有了上面的知识,你应该可以解开多种压缩文件了,下面对于 tar 系列的压缩文件作一个小结:

    1) 对于.tar结尾的文件

    tar -xf all.tar

    2) 对于 .gz 结尾的文件

    gzip -d all.gz
    gunzip all.gz

    3)对于 .tgz 或 .tar.gz 结尾的文件

    tar -xzf all.tar.gz
    tar -xzf all.tgz

    4) 对于 .bz2 结尾的文件

    bzip2 -d all.bz2
    bunzip2 all.bz2

    5) 对于 tar.bz2 结尾的文件

    tar -xjf all.tar.bz2

    6) 对于 .Z 结尾的文件

    uncompress all.Z

    7) 对于 .tar.Z 结尾的文件

    tar -xZf all.tar.z

    另外对于 Windows 下的常见压缩文件 .zip 和 .rar,Linux 也有相应的方法来解压它们:

    1) 对于 .zip

    linux 下提供了 zip 和 unzip 程序,zip 是压缩程序,unzip 是解压程序。它们的参数选项很多,这里只做简单介绍,依旧举例说明一下其用法:

    # zip all.zip *.jpg

    这条命令是将所有 .jpg 的文件压缩成一个 zip 包:

    # unzip all.zip

    这条命令是将 all.zip 中的所有文件解压出来。

    2) 对于 .rar

    要在 linux 下处理 .rar 文件,需要安装 RAR for Linux。下载地址:http://www.rarsoft.com/download.htm,下载后安装即可。

    # tar -xzpvf rarlinux-x64-5.6.b5.tar.gz
    # cd rar 
    # make

    这样就安装好了,安装后就有了 rar 和 unrar 这两个程序,rar 是压缩程序,unrar 是解压程序。它们的参数选项很多,这里只做简单介绍,依旧举例说明一下其用法:

    # rar a all *.jpg

    这条命令是将所有 .jpg 的文件压缩成一个 rar 包,名为 all.rar,该程序会将 .rar 扩展名将自动附加到包名后。

    # unrar e all.rar

    这条命令是将 all.rar 中的所有文件解压出来:


    扩展内容

    tar

    -c: 建立压缩档案 
    -x:解压 
    -t:查看内容 
    -r:向压缩归档文件末尾追加文件 
    -u:更新原压缩包中的文件

    这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。

    -z:有gzip属性的 
    -j:有bz2属性的 
    -Z:有compress属性的 
    -v:显示所有过程 
    -O:将文件解开到标准输出 

    下面的参数 -f 是必须的:

    -f: 使用档案名字,切记,这个参数是最后一个参数,后面只能接档案名。 

    # tar -cf all.tar *.jpg

    这条命令是将所有 .jpg 的文件打成一个名为 all.tar 的包。-c 是表示产生新的包,-f 指定包的文件名。

    # tar -rf all.tar *.gif 

    这条命令是将所有 .gif 的文件增加到 all.tar 的包里面去。-r 是表示增加文件的意思。

    # tar -uf all.tar logo.gif 

    这条命令是更新原来 tar 包 all.tar 中 logo.gif 文件,-u 是表示更新文件的意思。

    # tar -tf all.tar 

    这条命令是列出 all.tar 包中所有文件,-t 是列出文件的意思。

    # tar -xf all.tar 

    这条命令是解出 all.tar 包中所有文件,-x 是解开的意思。

    压缩

    tar –cvf jpg.tar *.jpg       // 将目录里所有jpg文件打包成 tar.jpg 
    tar –czf jpg.tar.gz *.jpg    // 将目录里所有jpg文件打包成 jpg.tar 后,并且将其用 gzip 压缩,生成一个 gzip 压缩过的包,命名为 jpg.tar.gz 
    tar –cjf jpg.tar.bz2 *.jpg   // 将目录里所有jpg文件打包成 jpg.tar 后,并且将其用 bzip2 压缩,生成一个 bzip2 压缩过的包,命名为jpg.tar.bz2 
    tar –cZf jpg.tar.Z *.jpg     // 将目录里所有 jpg 文件打包成 jpg.tar 后,并且将其用 compress 压缩,生成一个 umcompress 压缩过的包,命名为jpg.tar.Z 
    rar a jpg.rar *.jpg          // rar格式的压缩,需要先下载 rar for linux 
    zip jpg.zip *.jpg            // zip格式的压缩,需要先下载 zip for linux

    解压

    tar –xvf file.tar         // 解压 tar 包 
    tar -xzvf file.tar.gz     // 解压 tar.gz 
    tar -xjvf file.tar.bz2    // 解压 tar.bz2 
    tar –xZvf file.tar.Z      // 解压 tar.Z 
    unrar e file.rar          // 解压 rar 
    unzip file.zip            // 解压 zip 

    总结

    1、*.tar 用 tar –xvf 解压 
    2、*.gz 用 gzip -d或者gunzip 解压 
    3、*.tar.gz和*.tgz 用 tar –xzf 解压 
    4、*.bz2 用 bzip2 -d或者用bunzip2 解压 
    5、*.tar.bz2用tar –xjf 解压 
    6、*.Z 用 uncompress 解压 
    7、*.tar.Z 用tar –xZf 解压 
    8、*.rar 用 unrar e解压 
    9、*.zip 用 unzip 解压
  • 进程管理工具Supervisor使用教程

    Supervisor 是 Linux/Unix 系统下的一个进程管理工具。可以很方便的监听、启动、停止和重启一个或多个进程。通过 Supervisor 管理的进程,当进程意外被 Kill 时,Supervisor 会自动将它重启,可以很方便地做到进程自动恢复的目的,而无需自己编写 shell 脚本来管理进程。

    安装 Supervisor

    这里仅举例 CentOS 系统下的安装方式:

    # 安装 epel 源,如果此前安装过,此步骤跳过
    yum install -y epel-release
    yum install -y supervisor  

    创建一个配置文件

    cp /etc/supervisord.conf /etc/supervisord.d/supervisord.conf

    编辑新复制出来的配置文件 /etc/supervisord.d/supervisord.conf,并在文件结尾处添加以下内容后保存文件:

    # 新建一个应用并设置一个名称,这里设置为 hyperf
    [program:hyperf]
    # 设置命令在指定的目录内执行 
    directory=/var/www/hyperf/ 
    # 这里为您要管理的项目的启动命令 
    command=php ./bin/hyperf.php start 
    # 以哪个用户来运行该进程 
    user=root 
    # supervisor 启动时自动该应用 
    autostart=true 
    # 进程退出后自动重启进程 
    autorestart=true 
    # 进程持续运行多久才认为是启动成功 
    startsecs=1 
    # 重试次数 startretries=3 
    # stderr 日志输出位置 
    stderr_logfile=/var/www/hyperf/runtime/stderr.log 
    # stdout 日志输出位置 
    stdout_logfile=/var/www/hyperf/runtime/stdout.log

    建议同时增大配置文件中的 minfds 配置项,默认为 1024。同时也应该修改系统的 unlimit,防止出现 Failed to open stream: Too many open files 的问题。

    启动 Supervisor

    运行下面的命令基于配置文件启动 Supervisor 程序:

    supervisord -c /etc/supervisord.d/supervisord.conf

    使用 supervisorctl 管理项目

    # 启动 hyperf 应用
    supervisorctl start hyperf
    # 重启 hyperf 应用
    supervisorctl restart hyperf
    # 停止 hyperf 应用
    supervisorctl stop hyperf  
    # 查看所有被管理项目运行状态
    supervisorctl status
    # 重新加载配置文件
    supervisorctl update
    # 重新启动所有程序
    supervisorctl reload
  • 道设计模式面试题总结(含答案解析和思维导图)

    Q1:设计模式有哪些原则?

    开闭原则:OOP 中最基础的原则,指一个软件实体(类、模块、方法等)应该对扩展开放,对修改关闭。强调用抽象构建框架,用实现扩展细节,提高代码的可复用性和可维护性。

    单一职责原则:一个类、接口或方法只负责一个职责,降低代码复杂度以及变更引起的风险。

    依赖倒置原则:程序应该依赖于抽象类或接口,而不是具体的实现类。

    接口隔离原则:将不同功能定义在不同接口中实现接口隔离,避免了类依赖它不需要的接口,减少了接口之间依赖的冗余性和复杂性。

    里氏替换原则:开闭原则的补充,规定了任何父类可以出现的地方子类都一定可以出现,可以约束继承泛滥,加强程序健壮性。

    迪米特原则:也叫最少知道原则,每个模块对其他模块都要尽可能少地了解和依赖,降低代码耦合度。

    合成/聚合原则:尽量使用组合(has-a)/聚合(contains-a)而不是继承(is-a)达到软件复用的目的,避免滥用继承带来的方法污染和方法爆炸,方法污染指父类的行为通过继承传递给子类,但子类并不具备执行此行为的能力;方法爆炸指继承树不断扩大,底层类拥有的方法过于繁杂,导致很容易选择错误。


    Q2:设计模式的分类,你知道哪些设计模式?

    创建型: 在创建对象的同时隐藏创建逻辑,不使用 new 直接实例化对象,程序在判断需要创建哪些对象时更灵活。包括工厂/抽象工厂/单例/建造者/原型模式。

    结构型: 通过类和接口间的继承和引用实现创建复杂结构的对象。包括适配器/桥接模式/过滤器/组合/装饰器/外观/享元/代理模式。

    行为型: 通过类之间不同通信方式实现不同行为。包括责任链/命名/解释器/迭代器/中介者/备忘录/观察者/状态/策略/模板/访问者模式。


    Q3:说一说简单工厂模式

    简单工厂模式指由一个工厂对象来创建实例,客户端不需要关注创建逻辑,只需提供传入工厂的参数。

    适用于工厂类负责创建对象较少的情况,缺点是如果要增加新产品,就需要修改工厂类的判断逻辑,违背开闭原则,且产品多的话会使工厂类比较复杂。

    Calendar 抽象类的 getInstance 方法,调用 createCalendar 方法根据不同的地区参数创建不同的日历对象。

    Spring 中的 BeanFactory 使用简单工厂模式,根据传入一个唯一的标识来获得 Bean 对象。


    Q4:说一说工厂方法模式

    工厂方法模式指定义一个创建对象的接口,让接口的实现类决定创建哪种对象,让类的实例化推迟到子类中进行。

    客户端只需关心对应工厂而无需关心创建细节,主要解决了产品扩展的问题,在简单工厂模式中如果产品种类变多,工厂的职责会越来越多,不便于维护。

    Collection 接口这个抽象工厂中定义了一个抽象的 iterator 工厂方法,返回一个 Iterator 类的抽象产品。该方法通过 ArrayList 、HashMap 等具体工厂实现,返回 Itr、KeyIterator 等具体产品。

    Spring 的 FactoryBean 接口的 getObject 方法也是工厂方法。


    Q5:抽象工厂模式了解吗?

    抽象工厂模式指提供一个创建一系列相关或相互依赖对象的接口,无需指定它们的具体类。

    客户端不依赖于产品类实例如何被创建和实现的细节,主要用于系统的产品有多于一个的产品族,而系统只消费其中某一个产品族产品的情况。抽象工厂模式的缺点是不方便扩展产品族,并且增加了系统的抽象性和理解难度。

    java.sql.Connection 接口就是一个抽象工厂,其中包括很多抽象产品如 Statement、Blob、Savepoint 等。


    Q6:单例模式的特点是什么?

    单例模式属于创建型模式,一个单例类在任何情况下都只存在一个实例,构造方法必须是私有的、由自己创建一个静态变量存储实例,对外提供一个静态公有方法获取实例。

    优点是内存中只有一个实例,减少了开销,尤其是频繁创建和销毁实例的情况下并且可以避免对资源的多重占用。缺点是没有抽象层,难以扩展,与单一职责原则冲突。

    Spring 的 ApplicationContext 创建的 Bean 实例都是单例对象,还有 ServletContext、数据库连接池等也都是单例模式。

    Q7:单例模式有哪些实现?

    饿汉式:在类加载时就初始化创建单例对象,线程安全,但不管是否使用都创建对象可能会浪费内存。

    public class HungrySingleton {
        private HungrySingleton(){}
    
        private static HungrySingleton instance = new HungrySingleton();
    
        public static HungrySingleton getInstance() {
            return instance;
        }
    }

    懒汉式:在外部调用时才会加载,线程不安全,可以加锁保证线程安全但效率低。

    public class LazySingleton {
        private LazySingleton(){}
    
        private static LazySingleton instance;
    
        public static LazySingleton getInstance() {
            if(instance == null) {
                instance = new LazySingleton();
            }
            return instance;
        }
    }

    双重检查锁:使用 volatile 以及多重检查来减小锁范围,提升效率。

    public class DoubleCheckSingleton {
        private DoubleCheckSingleton(){}
    
        private volatile static DoubleCheckSingleton instance;
    
        public static DoubleCheckSingleton getInstance() {
            if(instance == null) {
                synchronized (DoubleCheckSingleton.class) {
                    if (instance == null) {
                        instance = new DoubleCheckSingleton();
                    }
                }
            }
            return instance;
        }
    }

    静态内部类:同时解决饿汉式的内存浪费问题和懒汉式的线程安全问题。

    public class StaticSingleton {
        private StaticSingleton(){}
    
        public static StaticSingleton getInstance() {
            return StaticClass.instance;
        }
    
        private static class StaticClass {
            private static final StaticSingleton instance = new StaticSingleton();
        }
    }

    枚举:《Effective Java》提倡的方式,不仅能避免线程安全问题,还能防止反序列化重新创建新的对象,绝对防止多次实例化,也能防止反射破解单例的问题。

    public enum EnumSingleton {
        INSTANCE;
    }

    Q8:讲一讲代理模式

    代理模式属于结构型模式,为其他对象提供一种代理以控制对这个对象的访问。优点是可以增强目标对象的功能,降低代码耦合度,扩展性好。缺点是在客户端和目标对象之间增加代理对象会导致请求处理速度变慢,增加系统复杂度。

    Spring 利用动态代理实现 AOP,如果 Bean 实现了接口就使用 JDK 代理,否则使用 CGLib 代理。

    静态代理:代理对象持有被代理对象的引用,调用代理对象方法时也会调用被代理对象的方法,但是会在被代理对象方法的前后增加其他逻辑。需要手动完成,在程序运行前就已经存在代理类的字节码文件,代理类和被代理类的关系在运行前就已经确定了。 缺点是一个代理类只能为一个目标服务,如果要服务多种类型会增加工作量。

    动态代理:动态代理在程序运行时通过反射创建具体的代理类,代理类和被代理类的关系在运行前是不确定的。动态代理的适用性更强,主要分为 JDK 动态代理和 CGLib 动态代理。

    • JDK 动态代理:通过 Proxy 类的 newInstance 方法获取一个动态代理对象,需要传入三个参数,被代理对象的类加载器、被代理对象实现的接口,以及一个 InvocationHandler 调用处理器来指明具体的逻辑,相比静态代理的优势是接口中声明的所有方法都被转移到 InvocationHandler 的 invoke 方法集中处理。
    • CGLib 动态代理:JDK 动态代理要求实现被代理对象的接口,而 CGLib 要求继承被代理对象,如果一个类是 final 类则不能使用 CGLib 代理。两种代理都在运行期生成字节码,JDK 动态代理直接写字节码,而 CGLib 动态代理使用 ASM 框架写字节码,ASM 的目的是生成、转换和分析以字节数组表示的已编译 Java 类。 JDK 动态代理调用代理方法通过反射机制实现,而 GCLib 动态代理通过 FastClass 机制直接调用方法,它为代理类和被代理类各生成一个类,该类为代理类和被代理类的方法分配一个 int 参数,调用方法时可以直接定位,因此调用效率更高。

    Q9:讲一讲装饰器模式

    装饰器模式属于结构型模式,在不改变原有对象的基础上将功能附加到对象,相比继承可以更加灵活地扩展原有对象的功能。

    装饰器模式适合的场景:在不想增加很多子类的前提下扩展一个类的功能。

    java.io 包中,InputStream 字节输入流通过装饰器 BufferedInputStream 增强为缓冲字节输入流。


    Q10:装饰器模式和动态代理的区别?

    装饰器模式的关注点在于给对象动态添加方法,而动态代理更注重对象的访问控制。动态代理通常会在代理类中创建被代理对象的实例,而装饰器模式会将装饰者作为构造方法的参数。


    Q11:讲一讲适配器模式

    适配器模式属于结构型模式,它作为两个不兼容接口之间的桥梁,结合了两个独立接口的功能,将一个类的接口转换成另外一个接口使得原本由于接口不兼容而不能一起工作的类可以一起工作。

    缺点是过多使用适配器会让系统非常混乱,不易整体把握。

    java.io 包中,InputStream 字节输入流通过适配器 InputStreamReader 转换为 Reader 字符输入流。

    Spring MVC 中的 HandlerAdapter,由于 handler 有很多种形式,包括 Controller、HttpRequestHandler、Servlet 等,但调用方式又是确定的,因此需要适配器来进行处理,根据适配规则调用 handle 方法。

    Arrays.asList 方法,将数组转换为对应的集合(注意不能使用修改集合的方法,因为返回的 ArrayList 是 Arrays 的一个内部类)。


    Q12:适配器模式和和装饰器模式以及代理模式的区别?

    适配器模式没有层级关系,适配器和被适配者没有必然连续,满足 has-a 的关系,解决不兼容的问题,是一种后置考虑。

    装饰器模式具有层级关系,装饰器与被装饰者实现同一个接口,满足 is-a 的关系,注重覆盖和扩展,是一种前置考虑。

    适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。


    Q13:讲一讲策略模式

    策略模式属于行为型模式,定义了一系列算法并封装起来,之间可以互相替换。策略模式主要解决在有多种算法相似的情况下,使用 if/else 所带来的难以维护。

    优点是算法可以自由切换,可以避免使用多重条件判断并且扩展性良好,缺点是策略类会增多并且所有策略类都需要对外暴露。

    在集合框架中,经常需要通过构造方法传入一个比较器 Comparator 进行比较排序。Comparator 就是一个抽象策略,一个类通过实现该接口并重写 compare 方法成为具体策略类。

    创建线程池时,需要传入拒绝策略,当创建新线程使当前运行的线程数超过 maximumPoolSize 时会使用相应的拒绝策略处理。


    Q14:讲一讲模板模式

    模板模式属于行为型模式,使子类可以在不改变算法结构的情况下重新定义算法的某些步骤,适用于抽取子类重复代码到公共父类。

    优点是可以封装固定不变的部分,扩展可变的部分。缺点是每一个不同实现都需要一个子类维护,会增加类的数量。

    为防止恶意操作,一般模板方法都以 final 修饰。

    HttpServlet 定义了一套处理 HTTP 请求的模板,service 方法为模板方法,定义了处理HTTP请求的基本流程,doXXX 等方法为基本方法,根据请求方法的类型做相应的处理,子类可重写这些方法。


    Q15:讲一讲观察者模式

    观察者模式属于行为型模式,也叫发布订阅模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。主要解决一个对象状态改变给其他对象通知的问题,缺点是如果被观察者对象有很多的直接和间接观察者的话通知很耗时, 如果存在循环依赖的话可能导致系统崩溃,另外观察者无法知道目标对象具体是怎么发生变化的。

    ServletContextListener 能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用。当 Servlet 容器启动 Web 应用时调用 contextInitialized 方法,终止时调用 contextDestroyed 方法。

  • 切换github账号后,push时403错误

    如果你在多个github账户之间切换,并在不同的github上克隆了仓库时,那么在提交代码的时候就会容易出现403错误,如下:

    image

    这个错误信息其实很明显,就是你要提交的github和你当前的github不是一个账号,我在网上搜索一下,也有很多种解决办法,下面介绍其中一种,亲测有效:
    打开终端输入:

    rundll32.exe keymgr.dll,KRShowKeyMgr
    

    在弹出的框中选择github并编辑

    image

    在下拉框中选择需要的账户,输入密码,点击确定

    image
    再重新push就可以成功了。

  • rsync 用法教程

    一、简介

    rsync 是一个常用的 Linux 应用程序,用于文件同步。

    它可以在本地计算机与远程计算机之间,或者两个本地目录之间同步文件(但不支持两台远程计算机之间的同步)。它也可以当作文件复制工具,替代cpmv命令。

    它名称里面的r指的是 remote,rsync 其实就是”远程同步”(remote sync)的意思。与其他文件传输工具(如 FTP 或 scp)不同,rsync 的最大特点是会检查发送方和接收方已有的文件,仅传输有变动的部分(默认规则是文件大小或修改时间有变动)。

    二、安装

    如果本机或者远程计算机没有安装 rsync,可以用下面的命令安装。

    
    # Debian
    $ sudo apt-get install rsync
    
    # Red Hat
    $ sudo yum install rsync
    
    # Arch Linux
    $ sudo pacman -S rsync
    

    注意,传输的双方都必须安装 rsync。

    三、基本用法

    3.1 -r 参数

    本机使用 rsync 命令时,可以作为cpmv命令的替代方法,将源目录同步到目标目录。

    
    $ rsync -r source destination
    

    上面命令中,-r表示递归,即包含子目录。注意,-r是必须的,否则 rsync 运行不会成功。source目录表示源目录,destination表示目标目录。

    如果有多个文件或目录需要同步,可以写成下面这样。

    
    $ rsync -r source1 source2 destination
    

    上面命令中,source1source2都会被同步到destination目录。

    3.2 -a 参数

    -a参数可以替代-r,除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等)。由于 rsync 默认使用文件大小和修改时间决定文件是否需要更新,所以-a-r更有用。下面的用法才是常见的写法。

    
    $ rsync -a source destination
    

    目标目录destination如果不存在,rsync 会自动创建。执行上面的命令后,源目录source被完整地复制到了目标目录destination下面,即形成了destination/source的目录结构。

    如果只想同步源目录source里面的内容到目标目录destination,则需要在源目录后面加上斜杠。

    
    $ rsync -a source/ destination
    

    上面命令执行后,source目录里面的内容,就都被复制到了destination目录里面,并不会在destination下面创建一个source子目录。

    3.3 -n 参数

    如果不确定 rsync 执行后会产生什么结果,可以先用-n--dry-run参数模拟执行的结果。

    
    $ rsync -anv source/ destination
    

    上面命令中,-n参数模拟命令执行的结果,并不真的执行命令。-v参数则是将结果输出到终端,这样就可以看到哪些内容会被同步。

    3.4 --delete 参数

    默认情况下,rsync 只确保源目录的所有内容(明确排除的文件除外)都复制到目标目录。它不会使两个目录保持相同,并且不会删除文件。如果要使得目标目录成为源目录的镜像副本,则必须使用--delete参数,这将删除只存在于目标目录、不存在于源目录的文件。

    
    $ rsync -av --delete source/ destination
    

    上面命令中,--delete参数会使得destination成为source的一个镜像。

    四、排除文件

    4.1 --exclude 参数

    有时,我们希望同步时排除某些文件或目录,这时可以用--exclude参数指定排除模式。

    
    $ rsync -av --exclude='*.txt' source/ destination
    # 或者
    $ rsync -av --exclude '*.txt' source/ destination
    

    上面命令排除了所有 TXT 文件。

    注意,rsync 会同步以”点”开头的隐藏文件,如果要排除隐藏文件,可以这样写--exclude=".*"

    如果要排除某个目录里面的所有文件,但不希望排除目录本身,可以写成下面这样。

    
    $ rsync -av --exclude 'dir1/*' source/ destination
    

    多个排除模式,可以用多个--exclude参数。

    
    $ rsync -av --exclude 'file1.txt' --exclude 'dir1/*' source/ destination
    

    多个排除模式也可以利用 Bash 的大扩号的扩展功能,只用一个--exclude参数。

    
    $ rsync -av --exclude={'file1.txt','dir1/*'} source/ destination
    

    如果排除模式很多,可以将它们写入一个文件,每个模式一行,然后用--exclude-from参数指定这个文件。

    
    $ rsync -av --exclude-from='exclude-file.txt' source/ destination
    

    4.2 --include 参数

    --include参数用来指定必须同步的文件模式,往往与--exclude结合使用。

    
    $ rsync -av --include="*.txt" --exclude='*' source/ destination
    

    上面命令指定同步时,排除所有文件,但是会包括 TXT 文件。

    五、远程同步

    5.1 SSH 协议

    rsync 除了支持本地两个目录之间的同步,也支持远程同步。它可以将本地内容,同步到远程服务器。

    
    $ rsync -av source/ username@remote_host:destination
    

    也可以将远程内容同步到本地。

    
    $ rsync -av username@remote_host:source/ destination
    

    rsync 默认使用 SSH 进行远程登录和数据传输。

    由于早期 rsync 不使用 SSH 协议,需要用-e参数指定协议,后来才改的。所以,下面-e ssh可以省略。

    
    $ rsync -av -e ssh source/ user@remote_host:/destination
    

    但是,如果 ssh 命令有附加的参数,则必须使用-e参数指定所要执行的 SSH 命令。

    
    $ rsync -av -e 'ssh -p 2234' source/ user@remote_host:/destination
    

    上面命令中,-e参数指定 SSH 使用2234端口。

    5.2 rsync 协议

    除了使用 SSH,如果另一台服务器安装并运行了 rsync 守护程序,则也可以用rsync://协议(默认端口873)进行传输。具体写法是服务器与目标目录之间使用双冒号分隔::

    
    $ rsync -av source/ 192.168.122.32::module/destination
    

    注意,上面地址中的module并不是实际路径名,而是 rsync 守护程序指定的一个资源名,由管理员分配。

    如果想知道 rsync 守护程序分配的所有 module 列表,可以执行下面命令。

    
    $ rsync rsync://192.168.122.32
    

    rsync 协议除了使用双冒号,也可以直接用rsync://协议指定地址。

    
    $ rsync -av source/ rsync://192.168.122.32/module/destination
    

    六、增量备份

    rsync 的最大特点就是它可以完成增量备份,也就是默认只复制有变动的文件。

    除了源目录与目标目录直接比较,rsync 还支持使用基准目录,即将源目录与基准目录之间变动的部分,同步到目标目录。

    具体做法是,第一次同步是全量备份,所有文件在基准目录里面同步一份。以后每一次同步都是增量备份,只同步源目录与基准目录之间有变动的部分,将这部分保存在一个新的目标目录。这个新的目标目录之中,也是包含所有文件,但实际上,只有那些变动过的文件是存在于该目录,其他没有变动的文件都是指向基准目录文件的硬链接。

    --link-dest参数用来指定同步时的基准目录。

    
    $ rsync -a --delete --link-dest /compare/path /source/path /target/path
    

    上面命令中,--link-dest参数指定基准目录/compare/path,然后源目录/source/path跟基准目录进行比较,找出变动的文件,将它们拷贝到目标目录/target/path。那些没变动的文件则会生成硬链接。这个命令的第一次备份时是全量备份,后面就都是增量备份了。

    下面是一个脚本示例,备份用户的主目录。

    
    #!/bin/bash
    
    # A script to perform incremental backups using rsync
    
    set -o errexit
    set -o nounset
    set -o pipefail
    
    readonly SOURCE_DIR="${HOME}"
    readonly BACKUP_DIR="/mnt/data/backups"
    readonly DATETIME="$(date '+%Y-%m-%d_%H:%M:%S')"
    readonly BACKUP_PATH="${BACKUP_DIR}/${DATETIME}"
    readonly LATEST_LINK="${BACKUP_DIR}/latest"
    
    mkdir -p "${BACKUP_DIR}"
    
    rsync -av --delete \
      "${SOURCE_DIR}/" \
      --link-dest "${LATEST_LINK}" \
      --exclude=".cache" \
      "${BACKUP_PATH}"
    
    rm -rf "${LATEST_LINK}"
    ln -s "${BACKUP_PATH}" "${LATEST_LINK}"
    

    上面脚本中,每一次同步都会生成一个新目录${BACKUP_DIR}/${DATETIME},并将软链接${BACKUP_DIR}/latest指向这个目录。下一次备份时,就将${BACKUP_DIR}/latest作为基准目录,生成新的备份目录。最后,再将软链接${BACKUP_DIR}/latest指向新的备份目录。

    七、配置项

    -a--archive参数表示存档模式,保存所有的元数据,比如修改时间(modification time)、权限、所有者等,并且软链接也会同步过去。

    --append参数指定文件接着上次中断的地方,继续传输。

    --append-verify参数跟--append参数类似,但会对传输完成后的文件进行一次校验。如果校验失败,将重新发送整个文件。

    -b--backup参数指定在删除或更新目标目录已经存在的文件时,将该文件更名后进行备份,默认行为是删除。更名规则是添加由--suffix参数指定的文件后缀名,默认是~

    --backup-dir参数指定文件备份时存放的目录,比如--backup-dir=/path/to/backups

    --bwlimit参数指定带宽限制,默认单位是 KB/s,比如--bwlimit=100

    -c--checksum参数改变rsync的校验方式。默认情况下,rsync 只检查文件的大小和最后修改日期是否发生变化,如果发生变化,就重新传输;使用这个参数以后,则通过判断文件内容的校验和,决定是否重新传输。

    --delete参数删除只存在于目标目录、不存在于源目标的文件,即保证目标目录是源目标的镜像。

    -e参数指定使用 SSH 协议传输数据。

    --exclude参数指定排除不进行同步的文件,比如--exclude="*.iso"

    --exclude-from参数指定一个本地文件,里面是需要排除的文件模式,每个模式一行。

    --existing--ignore-non-existing参数表示不同步目标目录中不存在的文件和目录。

    -h参数表示以人类可读的格式输出。

    -h--help参数返回帮助信息。

    -i参数表示输出源目录与目标目录之间文件差异的详细情况。

    --ignore-existing参数表示只要该文件在目标目录中已经存在,就跳过去,不再同步这些文件。

    --include参数指定同步时要包括的文件,一般与--exclude结合使用。

    --link-dest参数指定增量备份的基准目录。

    -m参数指定不同步空目录。

    --max-size参数设置传输的最大文件的大小限制,比如不超过200KB(--max-size='200k')。

    --min-size参数设置传输的最小文件的大小限制,比如不小于10KB(--min-size=10k)。

    -n参数或--dry-run参数模拟将要执行的操作,而并不真的执行。配合-v参数使用,可以看到哪些内容会被同步过去。

    -P参数是--progress--partial这两个参数的结合。

    --partial参数允许恢复中断的传输。不使用该参数时,rsync会删除传输到一半被打断的文件;使用该参数后,传输到一半的文件也会同步到目标目录,下次同步时再恢复中断的传输。一般需要与--append--append-verify配合使用。

    --partial-dir参数指定将传输到一半的文件保存到一个临时目录,比如--partial-dir=.rsync-partial。一般需要与--append--append-verify配合使用。

    --progress参数表示显示进展。

    -r参数表示递归,即包含子目录。

    --remove-source-files参数表示传输成功后,删除发送方的文件。

    --size-only参数表示只同步大小有变化的文件,不考虑文件修改时间的差异。

    --suffix参数指定文件名备份时,对文件名添加的后缀,默认是~

    -u--update参数表示同步时跳过目标目录中修改时间更新的文件,即不同步这些有更新的时间戳的文件。

    -v参数表示输出细节。-vv表示输出更详细的信息,-vvv表示输出最详细的信息。

    --version参数返回 rsync 的版本。

    -z参数指定同步时压缩数据。

  • PhpStorm折叠展开所有函数或者方法以及函数跳转

    windows下按下快捷`Ctrl`+`Shift`+`-`,这样就能折叠所有代码了。

    windows下按下快捷`Ctrl`+`Shift`+`+`,这样就能恢复打开所有代码了。

    在点击跳转函数后返回原位置

    Ctrl  Alt   ⬅左箭头