java-设计模式之-桥接模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html

背景

设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:

  • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
  • 第二种设计方案是根据实际需要对形状和颜色进行组合

对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。

java-设计模式之-外观模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/facade.html

定义

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。

java-设计模式之-命令模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html

背景

在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。

java-设计模式之-抽象工厂模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/abstract_factory.html

背景

  • 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

    为了更清晰地理解工厂方法模式,需要先引入两个概念:

    • 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
    • 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
  • 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
  • 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
  • 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

java-设计模式之-工程方法模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/factory_method.html

背景

现在对简单工厂模式进行修改,不再设计一个按钮工厂类来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成,我们先定义一个抽象的按钮工厂类,再定义具体的工厂类来生成圆形按钮、矩形按钮、菱形按钮等,它们实现在抽象按钮工厂类中定义的方法。这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新按钮的实例,这一特点无疑使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。

java-设计模式之-简单工程模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/simple_factory.html

背景

考虑一个简单的软件应用场景,一个软件系统可以提供多个外观不同的按钮(如圆形按钮、矩形按钮、菱形按钮等), 这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以呈现不同的外观,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。

java-设计模式之-装饰者模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/decorator.html

背景

一般有两种方式可以实现给一个类或对象增加行为:

  • 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
  • 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
    装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

nginx缓存功能介绍

介绍

当启用了Nginx的缓存功能时,Nginx会将后端服务的响应保存在本地磁盘上,在后续的请求中只有请求满足缓存的条件就会命中缓存,Nginx不会再将请求转发到后端的服务上。

启用响应缓存

要开始Nginx响应缓存,我们需要在http配置块中添加配置指令proxy_cache_path。该指令的第一个参数必须是一个本机文件系统路径。参数keys_zone也是必须的,用来设置共享内存缓存区的名称和大小。 该内存区域是用来保存缓存条目的原信息的。例如:

http {
    ...
    proxy_cache_path /path/to/cache levels=1:2 keys_zone=one:10m max_size=10g
             inactive=60m use_temp_path=off;
}

配置好proxy_cache_path后,我们还需要配置proxy_cache指令,语法如下:

Syntax:    proxy_cache zone | off;
Default:    
proxy_cache off;
Context:    http, server, location    

例子:

http {
    ...
    proxy_cache_path /data/nginx/cache keys_zone=one:10m;

    server {
        proxy_cache one;
        location / {
            proxy_pass http://localhost:8000;
        }
    }
}

proxy_cache指令有两个参数zoneoffzone的取值是proxy_cache_path指令中指定的共享内存区域名称的值(上例中的one), 如果取值为off则表示禁用缓存功能(注意限制范围)。

proxy_cache_path指令的完整语法如下:

Syntax:    proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default:    -
Context:    http

Nginx对缓存的处理

Nginx针对响应缓存有两个处理动作

  • 缓存管理器会定时检查缓存的状态。如果缓存的内容大小达到了指令proxy_cache_path的参数max-size指定的值,则缓存管理器会根据LRU算法删除缓存的内容。 在检查的间隔时间内,总的缓存内容大小可以临时超过设定的大小阈值。
  • 缓存加载器只在Nginx启动的时候执行一次,将缓存内容的原信息加载到指定的共享内存区内。一次将所有的缓存内容加载到内存中会耗费大量的资源,并且会影响Nginx启动后几分钟内的性能。为了避免这种问题可以通过在指令proxy_cache_path后添加下面的参数:
    • loader_threshold – 缓存加载器加载缓存内容的最大执行时间(单位是毫秒,默认值是200毫秒)。
    • loader_files – 在缓存加载器加载缓存内容的执行时间间隔内,最多能加载多少个缓存条目,默认100。
    • loader_sleeps – 每两次执行的时间间隔, 单位是毫秒 (默认50毫秒)

例子:

proxy_cache_path /data/nginx/cache keys_zone=one:10m loader_threshold=300 loader_files=200;

指定缓存条件

默认情况下,Nginx会缓存所有第一次通过HTTP GET 和 HEAD 方法发起的请求。Nginx将请求的完整字符串作为缓存内容的KEY。如果后面的请求和缓存的内容拥有相同的KEY,则Nginx会将缓存的内容发送给客户端。我们也可以在http, server,location块内包含各种指令来控制哪些响应可以被缓存。

可以通过使用指令proxy_cache_key来控制缓存KEY的生成规则:

proxy_cache_key "$host$request_uri$cookie_user";

可以通过指令proxy_cache_min_uses 指定一个请求的响应被缓存前的最小访问次数:

proxy_cache_min_uses 5;

可以通过指令proxy_cache_methods 指定只有哪些HTTP请求类型才能被缓存:

proxy_cache_methods GET HEAD POST;    

限制或旁路缓存

默认情况下响应内容会拥有被缓存起来,除非缓存内容的大小超过了指定的配置大小,超过以后会根据LRU算法进行删除。单我们也可以通过在http,server,location中配置统一的过期时间:

proxy_cache_valid 200 302 10m;
proxy_cache_valid 404      1m;    

上面的配置指定了当后端服务的响应是200,302时,缓存的有效期是10分钟;404 缓存有效期为1分钟。

proxy_cache_valid any 5m;

也可以不区分后端的响应码,此时可以用any来指代。

可以通过指令proxy_cache_bypass指定Nginx使用缓存的条件,如下:

proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;    

该指令的每个参数都指定了一个条件,只有请求满足其中的任何一个条件,并且参数的值不是0,则Nginx会把请求转发到后端的服务而不会使用缓存。

可以通过指令proxy_no_cache指定哪些请求不需要Nginx来缓存,配置格式和proxy_cache_bypass 类似:

proxy_no_cache $http_pragma $http_authorization;

清除缓存内容

Nginx提供了清除过期缓存内容的功能。 这个功能是非常有必要的,一方面我们可以手动删除过期的缓存内容;另一方面我们当我们后端的内容已经改变了,我们就可以通过删除老的缓存来使用新的内容。缓存的删除是通过特殊的HTTP请求方法purge或自定义的请求头来实现的。

下面的配置演示了通过HTTP方法purge来删除缓存内容

  1. 在HTTP配合块内定义了一个新的变量$purge_method, 改变量的值依赖变量$request_method的值

    1
    2
    3
    4
    5
    6
    7
    http {
    ...
    map $request_method $purge_method {
    PURGE 1;
    default 0;
    }
    }
  1. 在配置缓存功能的location中, 通过包含指令proxy_cache_purge来指定清除缓存请求的条件。在下面的配置例子中是通过变量$purge_method来控制的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
       server {
    listen 80;
    server_name www.example.com;

    location / {
    proxy_pass https://localhost:8002;
    proxy_cache mycache;

    proxy_cache_purge $purge_method;
    }
    }
    ```

    #### 发送清除命令

    当配置了`proxy_cache_purge`指令后,我们就可以通过发送缓存清除请求来删除缓存了。例如:

    $ curl -X PURGE -D – "https://www.example.com/*"
    //响应
    HTTP/1.1 204 No Content
    Server: nginx/1.5.7
    Date: Sat, 01 Dec 2015 16:33:04 GMT
    Connection: keep-alive

    在上面的例子中, 所有拥有相同URL部分的资源的缓存都会被删除(通过`*`号来指定的)。然而需要注意的是这些被删除的缓存条目不会被马上从磁盘上删除。它们或者被`purger`进程删除,或者在之后的访问中被删除掉或者在超过指令`proxy_cache_path`的参数`inactive`指定的过期时间后被删除。(这个很容易理解,如果删除的内容过大,就会造成Nginx性能的临时下降;其次是尽量不影响其它正常请求的处理)

    #### 限制缓存清除请求

    通常推荐配置可以发起缓存删除请求的客户端IP地址,来防止意外的缓存失效。

    geo $purge_allowed {
    default 0; # deny from other
    10.0.0.1 1; # allow from localhost
    192.168.0.0/24 1; # allow from 10.0.0.0/24
    }

    map $request_method $purge_method {
    PURGE $purge_allowed;
    default 0;
    }

    ### 完全删除缓存文件

    为了完全删除匹配`*`号的缓存文件, 我们需要启动一个指定的缓存清除进程。可以通过在指令`proxy_cache_path` 后面添加参数`purger=on`来启动该进程。

    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on;

    ### 缓存清除配置示例

    http {
    ...
    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on;

    map $request_method $purge_method {
    PURGE 1;
    default 0;
    }

    server {
    listen 80;
    server_name www.example.com;

    location / {
    proxy_pass https://localhost:8002;
    proxy_cache mycache;
    proxy_cache_purge $purge_method;
    }
    }

    geo $purge_allowed {
    default 0;
    10.0.0.1 1;
    192.168.0.0/24 1;
    }
    map $request_method $purge_method {
    PURGE $purge_allowed;
    default 0;
    }
    }

    ### Byte-Range

    Sometimes, the initial cache fill operation may take some time, especially for large files. When the first request starts downloading a part of a video file, next requests will have to wait for the entire file to be downloaded and put into the cache.

    NGINX makes it possible cache such range requests and gradually fill the cache with the cache slice module. The file is divided into smaller “slices”. Each range request chooses particular slices that would cover the requested range and, if this range is still not cached, put it into the cache. All other requests to these slices will take the response from the cache.

    To enable byte-range caching:

    1. Make sure your NGINX is compiled with the slice module.
    2. Specify the size of the slice with the slice directive:

    location / {

    slice  1m;
    

    }
    ```

The slice size should be adjusted reasonably enough to make slice download fast. A too small size may result in excessive memory usage and a large number of opened file descriptors while processing the request, a too large value may result in latency.

  1. Include the $slice_range variable to the cache key:

    proxy_cache_key $uri$is_args$args$slice_range;
    
  2. Enable caching of responses with 206 status code:

    proxy_cache_valid 200 206 1h;
    
  3. Enable passing range requests to the proxied server by passing the $slice_range variable in the Range header field:

    proxy_set_header  Range $slice_range;
    

完整配置

http {
    ...
    proxy_cache_path /data/nginx/cache keys_zone=one:10m loader_threshold=300 
                     loader_files=200 max_size=200m;

    server {
        listen 8080;
        proxy_cache one;

        location / {
            proxy_pass http://backend1;
        }

        location /some/path {
            proxy_pass http://backend2;
            proxy_cache_valid any 1m;
            proxy_cache_min_uses 3;
            proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
        }
    }
}

参考

https://www.nginx.com/blog/nginx-caching-guide/
https://www.nginx.com/resources/admin-guide/content-caching/
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache

java设计模式之-观察者模式

文章转自:https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html

背景

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

nginx配置rewrite指令详解

前言

Nginx 的配置指令非常多, 其中rewrite指令的使用频率非常高. 以前只是对该指令有简单的了解,没有详细查看该指令详细的使用方法.在
双11的秒杀配置中使用了该配置指令来做URL的跳转,但是感觉配置的有问题,重复进行了跳转.借此机会翻看Nginx官方文档学习该指令的用法.

|