• Fun论设计模式之2:代理模式(Proxy Pattern)与华为云API设计之一


      今天学习到了一个新的设计模式:代理模式。介绍借鉴了runoob的:

      意图:为其他对象提供一种代理以控制对这个对象的访问。

      主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

      何时使用:想在访问一个类时做一些控制。

      如何解决:增加中间层。

      关键代码:实现与被代理类组合。

      访问一个类是做一些控制,增加中间层,这种情况一般都出现在账号密码验证、令牌验证之类,需要检验或修改部分信息,但对业务结构没有改变的情况。

      Struts2的filter,还有SpringMVC的interceptor,以及Java的注解,本质上都是代理模式。

      这里有一个使用了代理模式的例子:

      之前为了给系统对接华为云API,设计了一套restful API的封装类,有多种封装类型,VPCUtil(虚拟私有云),ECSUtil(云服务器),SecurityGroupUtil(安全组),PublicIPUtil(公开IP),这几种请求不同的业务,但是都有一个相同点:操作之前要先登录,使用IAMUtil(身份验证)里的封装函数发送账号密码,返回有效期为24小时的token,这个token拿去请求其他业务(何时使用)。

      图1. 华为云API模块操作流程图

      每次开启服务器时都要获取一次token,并且每次请求华为云都要检查token是否过期,过期则重新更新token。

      如果这个操作是写在业务Util里面,每次操作都要在对象函数里面执行一次,像VPCUtil:

      1 import java.util.UUID;
      2 
      3 import org.json.JSONArray;
      4 import org.json.JSONException;
      5 import org.json.JSONObject;
      6 
      7 public class VPCUtil{
      8     
      9     private String username;
     10     
     11     private String password;
     12     
     13     private String token;
     14     
     15     private String projectId;
     16     
     17     private long overDate;
     18     
     19     public IAMUtil(){
     20     } 
     21     
     22     public IAMUtil(String username, String password){
     23         this.username = username;
     24         this.password = password;
     25         TokenAndProject tap = new IAMUtil().getToken(username,password);
     26         this.overDate = System.currentTimeMillis() + 23*60*60*1000;
     27         this.token = tap.getToken();
     28         this.projectId = tap.getProjectId();
     29     }
     30     
     31     /**
     32      * 
     33      * @Title createVPC
     34      * @Description 创建虚拟私有云
     35      * @param idx
     36      * @return vpc_id 虚拟私有云的ID
     37      */
     38     public String createVPC(int idx, String name_prefix) {
     39         this.checkAccount();
     40         JSONObject resjo = null;
     41         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs","{"vpc": {"name": "" + name_prefix + "-" + (1+idx) + "","cidr": "192.168.0.0/16"}}",token);
     42         String vpc_id = "";
     43         try {
     44             resjo = new JSONObject(res);
     45             vpc_id = resjo.getJSONObject("vpc").getString("id");
     46         } catch (JSONException e) {
     47             System.out.println(res);
     48             e.printStackTrace();
     49         }finally {
     50         }
     51         return vpc_id;
     52     }
     53     
     54     /**
     55      * 
     56      * @Title createVPC
     57      * @Description 创建虚拟私有云的子网
     58      * @param subNo 192.168.x.y 里面的x
     59      * @return vpc_id 虚拟私有云的ID
     60      */
     61     public NetWorkIds createSubnet(int idx, String vpc_id, int subNo, String name_prefix) {
     62         this.checkAccount();
     63         JSONObject resjo = null;
     64         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/subnets",
     65                 "{"subnet": {"name": "" + name_prefix + "-" + (subNo == 10 ? "manager" : "service") + "-" + (1+idx) + "","cidr": "192.168." + subNo + ".0/24","gateway_ip": "192.168." + subNo + ".254","vpc_id": "" + vpc_id + ""}}",token);
     66         String netId = "";
     67         String subnetId = "";
     68         try {
     69             resjo = new JSONObject(res);
     70             netId = resjo.getJSONObject("subnet").getString("id");
     71             subnetId = resjo.getJSONObject("subnet").getString("neutron_subnet_id");
     72         } catch (JSONException e) {
     73             System.out.println(res);
     74             e.printStackTrace();
     75         }finally {
     76         }
     77         return new NetWorkIds(netId,subnetId);
     78     }
     79     
     80     public NetWorkIds createSubnetFilter(int idx, String vpc_id, int subNo, String name_prefix) {
     81         this.checkAccount();
     82         NetWorkIds nids = createSubnet(idx, vpc_id, subNo, name_prefix);
     83         while(true) {
     84             String portsres = getPorts(nids.getNetId(), true);
     85             JSONArray ports = null;
     86             JSONArray fixed_ips = null;
     87             try {
     88                 ports = new JSONArray(portsres);
     89                 if(ports.length() <= 0)continue;
     90                 fixed_ips = ports.getJSONObject(0).getJSONArray("fixed_ips");
     91                 if(fixed_ips.length() <= 0)continue;
     92                 String ip_address = fixed_ips.getJSONObject(0).getString("ip_address");
     93                 int ip4 = Integer.parseInt(ip_address.split("\.")[3]);
     94                 System.out.println("I get the address : " + ip_address);
     95                 if((ip4 >= 1 && ip4 <= 4) || (ip4 >= 100 && ip4 <= 103)){
     96                     nids = new VPCUtil().createSubnet(token, projectId, idx, vpc_id, subNo, name_prefix);
     97                 }else {
     98                     break;
     99                 }
    100             } catch (JSONException e) {
    101                 System.out.println(portsres);
    102                 e.printStackTrace();
    103             }
    104         }
    105         
    106         return nids;
    107     }
    108     
    109     public String createVirtualIP(String net_id, String subnet_id, String ip) {
    110         this.checkAccount();
    111         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports",
    112                 "{"port": {"network_id": "" + net_id + "","device_owner": "neutron:VIP_PORT","name": "" + UUID.randomUUID().toString() + "","fixed_ips": [{"subnet_id": "" + subnet_id + "", "ip_address": "" + ip + ""}]}}", token);
    113         String new_port_id = "";
    114         try {
    115             new_port_id = new JSONObject(res).getJSONObject("port").getString("id");
    116         } catch (JSONException e) {
    117             System.out.println(res);
    118             e.printStackTrace();
    119         }
    120         return new_port_id;
    121     }    
    122     
    123     public void createVirtualIPport(String port_id, String ip1, String ip2) {
    124         this.checkAccount();
    125         RequestUtil.requestsPut("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports/" + port_id,
    126                 "{"port": {"allowed_address_pairs": [{"ip_address":"" + ip1 + ""},{"ip_address":"" + ip2 + ""}]}}", token);
    127     }
    128     
    129     /**
    130      * 
    131      * @Title getVPCs
    132      * @Description 获取虚拟私有云列表
    133      * @return vpcsInJSON 虚拟私有云列表的JOSN格式字符串
    134      */
    135     public String getVPCs() {
    136         this.checkAccount();
    137         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs", token);
    138         try {
    139             JSONObject resjo = new JSONObject(res);
    140             JSONArray vpcs = resjo.getJSONArray("vpcs");
    141             res = vpcs.toString();
    142         } catch (JSONException e) {
    143             System.out.println(res);
    144             e.printStackTrace();
    145         }
    146         return res;
    147     }
    148     
    149     public String getSubnets(String vpc_id) {
    150         this.checkAccount();
    151         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/subnets?project_id" + projectId + (vpc_id == null ? "" : "&vpc_id=" + vpc_id), token);
    152         try {
    153             JSONObject resjo = new JSONObject(res);
    154             JSONArray vpcs = resjo.getJSONArray("subnets");
    155             res = vpcs.toString();
    156         } catch (JSONException e) {
    157             System.out.println(res);
    158             e.printStackTrace();
    159         }
    160         return res;
    161     }
    162     
    163     public String getPorts(String network_id) {
    164         this.checkAccount();
    165         return getPorts(network_id, false);
    166     }
    167     
    168     public String getPorts(String network_id, boolean isDHCP) {
    169         this.checkAccount();
    170         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports?project_id=" + projectId + (network_id == null ? "" : "&network_id=" + network_id) + (isDHCP ? "&device_owner=network:dhcp" : ""), token);
    171         try {
    172             JSONObject resjo = new JSONObject(res);
    173             JSONArray vpcs = resjo.getJSONArray("ports");
    174             res = vpcs.toString();
    175         } catch (JSONException e) {
    176             System.out.println(res);
    177             e.printStackTrace();
    178         }
    179         return res;
    180     }
    181     
    182     public String deletePort(String token, String port_id) {
    183         this.checkAccount();
    184         System.out.println("deletePort start " + port_id);
    185         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports/" + port_id, token);
    186         System.out.println(res);
    187         System.out.println("deletePort end");
    188         return res;
    189     }
    190     
    191     public String deleteSubnet(String vpc_id, String network_id) {
    192         this.checkAccount();
    193         System.out.println("deleteSubnet start " + network_id);
    194         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs/"+ vpc_id +"/subnets/" + network_id, token);
    195         System.out.println(res);
    196         System.out.println("deleteSubnet end");
    197         return res;
    198     }
    199     
    200     public String deleteVPC(String vpc_id) {
    201         this.checkAccount();
    202         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs/" + vpc_id, token);
    203         System.out.println(res);
    204         return res;
    205     }
    206     
    207     private void checkAccount(){
    208         if(tap == null || System.currentTimeMillis() > overDate) {
    209             tap = new IAMUtil().getToken(this.username,this.password);
    210             this.token = tap.getToken();
    211             this.projectId = tap.getProjectId();
    212             this.overDate = System.currentTimeMillis() + 23*60*60*1000;
    213         }
    214     }
    215     
    216 }
    217 
    218 class NetWorkIds{
    219     String netId;
    220     String subnetId;
    221     public NetWorkIds(String netId, String subnetId) {
    222         super();
    223         this.netId = netId;
    224         this.subnetId = subnetId;
    225     }
    226     
    227     public String getNetId() {return netId;}
    228     public String getSubNetId() {return subnetId;}
    229 }
    View Code

      这里,每个操作前面都要执行checkAccount这个函数。如果这个业务要经常添加功能的话,每个函数都要在这里添加这个前置动作,很容易因为某些原因,把代码写错,也不利于维护。

      可以给这上面的所有代码做个代理,并且把username和password、token、projectId的可见性设置为protected,为后面的变量访问做准备。

      直接把函数写在代理的注入过程里面(如何解决),就可以在不用写前置代码的前提下执行token校验了;外部类调用代理过的对象。为了让cglib能代理成功,需要声明无参构造函数:

      1 import java.util.UUID;
      2 
      3 import org.json.JSONArray;
      4 import org.json.JSONException;
      5 import org.json.JSONObject;
      6 
      7 public class VPCUtil{
      8     
      9     protected String username;
     10     
     11     protected String password;
     12     
     13     protected String token;
     14     
     15     protected String projectId;
     16     
     17     protected long overDate;
     18     
     19     public IAMUtil(){
     20     } 
     21     
     22     public IAMUtil(String username, String password){
     23         this.username = username;
     24         this.password = password;
     25         TokenAndProject tap = new IAMUtil().getToken(username,password);
     26         this.overDate = System.currentTimeMillis() + 23*60*60*1000;
     27         this.token = tap.getToken();
     28         this.projectId = tap.getProjectId();
     29     }
     30     
     31     /**
     32      * 
     33      * @Title createVPC
     34      * @Description 创建虚拟私有云
     35      * @param idx
     36      * @return vpc_id 虚拟私有云的ID
     37      */
     38     public String createVPC(int idx, String name_prefix) {
     39         this.checkAccount();
     40         JSONObject resjo = null;
     41         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs","{"vpc": {"name": "" + name_prefix + "-" + (1+idx) + "","cidr": "192.168.0.0/16"}}",token);
     42         String vpc_id = "";
     43         try {
     44             resjo = new JSONObject(res);
     45             vpc_id = resjo.getJSONObject("vpc").getString("id");
     46         } catch (JSONException e) {
     47             System.out.println(res);
     48             e.printStackTrace();
     49         }finally {
     50         }
     51         return vpc_id;
     52     }
     53     
     54     /**
     55      * 
     56      * @Title createVPC
     57      * @Description 创建虚拟私有云的子网
     58      * @param subNo 192.168.x.y 里面的x
     59      * @return vpc_id 虚拟私有云的ID
     60      */
     61     public NetWorkIds createSubnet(int idx, String vpc_id, int subNo, String name_prefix) {
     62         this.checkAccount();
     63         JSONObject resjo = null;
     64         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/subnets",
     65                 "{"subnet": {"name": "" + name_prefix + "-" + (subNo == 10 ? "manager" : "service") + "-" + (1+idx) + "","cidr": "192.168." + subNo + ".0/24","gateway_ip": "192.168." + subNo + ".254","vpc_id": "" + vpc_id + ""}}",token);
     66         String netId = "";
     67         String subnetId = "";
     68         try {
     69             resjo = new JSONObject(res);
     70             netId = resjo.getJSONObject("subnet").getString("id");
     71             subnetId = resjo.getJSONObject("subnet").getString("neutron_subnet_id");
     72         } catch (JSONException e) {
     73             System.out.println(res);
     74             e.printStackTrace();
     75         }finally {
     76         }
     77         return new NetWorkIds(netId,subnetId);
     78     }
     79     
     80     public NetWorkIds createSubnetFilter(int idx, String vpc_id, int subNo, String name_prefix) {
     81         this.checkAccount();
     82         NetWorkIds nids = createSubnet(idx, vpc_id, subNo, name_prefix);
     83         while(true) {
     84             String portsres = getPorts(nids.getNetId(), true);
     85             JSONArray ports = null;
     86             JSONArray fixed_ips = null;
     87             try {
     88                 ports = new JSONArray(portsres);
     89                 if(ports.length() <= 0)continue;
     90                 fixed_ips = ports.getJSONObject(0).getJSONArray("fixed_ips");
     91                 if(fixed_ips.length() <= 0)continue;
     92                 String ip_address = fixed_ips.getJSONObject(0).getString("ip_address");
     93                 int ip4 = Integer.parseInt(ip_address.split("\.")[3]);
     94                 System.out.println("I get the address : " + ip_address);
     95                 if((ip4 >= 1 && ip4 <= 4) || (ip4 >= 100 && ip4 <= 103)){
     96                     nids = new VPCUtil().createSubnet(token, projectId, idx, vpc_id, subNo, name_prefix);
     97                 }else {
     98                     break;
     99                 }
    100             } catch (JSONException e) {
    101                 System.out.println(portsres);
    102                 e.printStackTrace();
    103             }
    104         }
    105         
    106         return nids;
    107     }
    108     
    109     public String createVirtualIP(String net_id, String subnet_id, String ip) {
    110         this.checkAccount();
    111         String res = RequestUtil.requestsPost("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports",
    112                 "{"port": {"network_id": "" + net_id + "","device_owner": "neutron:VIP_PORT","name": "" + UUID.randomUUID().toString() + "","fixed_ips": [{"subnet_id": "" + subnet_id + "", "ip_address": "" + ip + ""}]}}", token);
    113         String new_port_id = "";
    114         try {
    115             new_port_id = new JSONObject(res).getJSONObject("port").getString("id");
    116         } catch (JSONException e) {
    117             System.out.println(res);
    118             e.printStackTrace();
    119         }
    120         return new_port_id;
    121     }    
    122     
    123     public void createVirtualIPport(String port_id, String ip1, String ip2) {
    124         this.checkAccount();
    125         RequestUtil.requestsPut("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports/" + port_id,
    126                 "{"port": {"allowed_address_pairs": [{"ip_address":"" + ip1 + ""},{"ip_address":"" + ip2 + ""}]}}", token);
    127     }
    128     
    129     /**
    130      * 
    131      * @Title getVPCs
    132      * @Description 获取虚拟私有云列表
    133      * @return vpcsInJSON 虚拟私有云列表的JOSN格式字符串
    134      */
    135     public String getVPCs() {
    136         this.checkAccount();
    137         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs", token);
    138         try {
    139             JSONObject resjo = new JSONObject(res);
    140             JSONArray vpcs = resjo.getJSONArray("vpcs");
    141             res = vpcs.toString();
    142         } catch (JSONException e) {
    143             System.out.println(res);
    144             e.printStackTrace();
    145         }
    146         return res;
    147     }
    148     
    149     public String getSubnets(String vpc_id) {
    150         this.checkAccount();
    151         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/subnets?project_id" + projectId + (vpc_id == null ? "" : "&vpc_id=" + vpc_id), token);
    152         try {
    153             JSONObject resjo = new JSONObject(res);
    154             JSONArray vpcs = resjo.getJSONArray("subnets");
    155             res = vpcs.toString();
    156         } catch (JSONException e) {
    157             System.out.println(res);
    158             e.printStackTrace();
    159         }
    160         return res;
    161     }
    162     
    163     public String getPorts(String network_id) {
    164         this.checkAccount();
    165         return getPorts(network_id, false);
    166     }
    167     
    168     public String getPorts(String network_id, boolean isDHCP) {
    169         this.checkAccount();
    170         String res = RequestUtil.requestsGet("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports?project_id=" + projectId + (network_id == null ? "" : "&network_id=" + network_id) + (isDHCP ? "&device_owner=network:dhcp" : ""), token);
    171         try {
    172             JSONObject resjo = new JSONObject(res);
    173             JSONArray vpcs = resjo.getJSONArray("ports");
    174             res = vpcs.toString();
    175         } catch (JSONException e) {
    176             System.out.println(res);
    177             e.printStackTrace();
    178         }
    179         return res;
    180     }
    181     
    182     public String deletePort(String token, String port_id) {
    183         this.checkAccount();
    184         System.out.println("deletePort start " + port_id);
    185         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v2.0/ports/" + port_id, token);
    186         System.out.println(res);
    187         System.out.println("deletePort end");
    188         return res;
    189     }
    190     
    191     public String deleteSubnet(String vpc_id, String network_id) {
    192         this.checkAccount();
    193         System.out.println("deleteSubnet start " + network_id);
    194         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs/"+ vpc_id +"/subnets/" + network_id, token);
    195         System.out.println(res);
    196         System.out.println("deleteSubnet end");
    197         return res;
    198     }
    199     
    200     public String deleteVPC(String vpc_id) {
    201         this.checkAccount();
    202         String res = RequestUtil.requestsDelete("https://vpc.cn-south-1.myhuaweicloud.com/v1/" + projectId + "/vpcs/" + vpc_id, token);
    203         System.out.println(res);
    204         return res;
    205     }
    206     
    207     private void checkAccount(){
    208         if(tap == null || System.currentTimeMillis() > overDate) {
    209             tap = new IAMUtil().getToken(this.username,this.password);
    210             this.token = tap.getToken();
    211             this.projectId = tap.getProjectId();
    212             this.overDate = System.currentTimeMillis() + 23*60*60*1000;
    213         }
    214     }
    215     
    216 }
    217 
    218 class NetWorkIds{
    219     String netId;
    220     String subnetId;
    221     public NetWorkIds(String netId, String subnetId) {
    222         super();
    223         this.netId = netId;
    224         this.subnetId = subnetId;
    225     }
    226     
    227     public String getNetId() {return netId;}
    228     public String getSubNetId() {return subnetId;}
    229 }
    VPCUtil v0.2

      代理这个Util的类:

     1 import java.lang.reflect.Method;
     2 
     3 import org.springframework.cglib.proxy.Enhancer;
     4 import org.springframework.cglib.proxy.MethodInterceptor;
     5 import org.springframework.cglib.proxy.MethodProxy;
     6 
     7 public class TokenProxy {
     8     
     9     private VPCUtil VPCProxy = null;
    10     
    11     public TokenProxy(String username, String password) {
    12         Enhancer enhancer = new Enhancer();
    13         enhancer.setSuperclass(VPCUtil.class);
    14         // 设置enhancer的回调对象
    15         enhancer.setCallback(new MethodInterceptor() {
    16             private TokenAndProject tap = null;
    17             private long overDate = 0;
    18             @Override
    19             public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    20                 ((VPCUtil)sub).checkAccount();
    21                 Object res = methodProxy.invokeSuper(sub, objects);
    22                 return res;
    23             }
    24         });
    25         this.VPCProxy= (VPCUtil)enhancer.create();
    26     }
    27     
    28     public VPCUtil getVPCProxy() {
    29         return this.VPCProxy;
    30     }
    31 
    32 }
    TokenProxy

      但是如果运行这个类的函数,会出现StackOverFlowError错误:

    Exception in thread "main" java.lang.StackOverflowError
    	at zhyx_cloud.VPCUtil$$EnhancerByCGLIB$$a10b0367.checkAccount(<generated>)
    	at zhyx_cloud.TokenProxy$1.intercept(TokenProxy.java:22)
    	at zhyx_cloud.VPCUtil$$EnhancerByCGLIB$$a10b0367.checkAccount(<generated>)
    	at zhyx_cloud.TokenProxy$1.intercept(TokenProxy.java:22)
    	at zhyx_cloud.VPCUtil$$EnhancerByCGLIB$$a10b0367.checkAccount(<generated>)
    	at zhyx_cloud.TokenProxy$1.intercept(TokenProxy.java:22)
    	at zhyx_cloud.VPCUtil$$EnhancerByCGLIB$$a10b0367.checkAccount(<generated>)
    	at zhyx_cloud.TokenProxy$1.intercept(TokenProxy.java:22)
    	at zhyx_cloud.VPCUtil$$EnhancerByCGLIB$$a10b0367.checkAccount(<generated>)
    	at zhyx_cloud.TokenProxy$1.intercept(TokenProxy.java:22)

      问题出现在哪呢?实际上cglib代理这个函数时,传进来的第一参数也是经过代理的,执行这个对象的函数的话,这个函数会先进入代理注入环节,然后注入函数里面又会调用到这个函数,这就造成了死循环递归。

      就是说,在无法保证递归终点的情况下,注入函数里面不能调用被代理对象本身的函数,那就只能把整个函数都抄过来了(关键代码)。

     1 import java.lang.reflect.Method;
     2 
     3 import org.springframework.cglib.proxy.Enhancer;
     4 import org.springframework.cglib.proxy.MethodInterceptor;
     5 import org.springframework.cglib.proxy.MethodProxy;
     6 
     7 public class TokenProxy {
     8     
     9     private VPCUtil VPCProxy = null;
    10     
    11     public TokenProxy(String username, String password) {
    12         Enhancer enhancer = new Enhancer();
    13         enhancer.setSuperclass(VPCUtil.class);
    14         // 设置enhancer的回调对象
    15         enhancer.setCallback(new MethodInterceptor() {
    16             @Override
    17             public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    18                 if(tap == null || System.currentTimeMillis() > overDate) {
    19                     TokenAndProject tap = new IAMUtil().getToken(this.username,this.password);
    20                     VPCUtil myproxy = (VPCUtil)sub;
    21                     myproxy.token = tap.getToken();
    22                     myproxy.projectId = tap.getProjectId();
    23                     myproxy.overDate = System.currentTimeMillis() + 23*60*60*1000;
    24                 }
    25                 Object res = methodProxy.invokeSuper(sub, objects);
    26                 return res;
    27             }
    28         });
    29         this.VPCProxy= (VPCUtil)enhancer.create();
    30     }
    31     
    32     public VPCUtil getVPCProxy() {
    33         return this.VPCProxy;
    34     }
    35 
    36 }
    TokenProxy v0.2

      这里,没有对被代理对象的函数调用,没有循环注入的问题;同时也实现了修改内部属性的功能,使功能照常进行。

      这里违反了DRY(don't repeat yourself)规则,但是相对来说也没啥更好的方法;这个方法的代码量和出错率还是较低的,并且运行效果与原先代码相当。

     图2. 用0.2版本TokenProxy代理之后,华为云API模块操作流程图

      这种方法还是有一些优化空间,像图2所示,其他几个模块也要用这个,可以把这4个模块整合起来代理,这样优化级别就是模块等级了。

      优点: 1、职责清晰。 2、高扩展性。 3、智能化。

      缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。(Java要实现代理,就必须使用反射,这中间会涉及到类的加载,类在cglib中的字节码处理,运行时间较长)

      2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。(Spring的依赖注入内部不止要做代理,还要维护工厂生产的组件)

  • 相关阅读:
    解决“Caused by: org.gradle.api.plugins.UnknownPluginException: Plugin with id 'org.springframework.boot' not found.”
    linux随机生成密码
    NFS网络共享文件系统
    shell实现带颜色输出的进度条
    【AtCoder】 ARC 101
    【AtCoder】 ARC 102
    【AtCoder】 ARC 103
    20190814校内模拟赛
    「2019-8-13提高模拟赛」树 (tree)
    [PA2014]Fiolki
  • 原文地址:https://www.cnblogs.com/dgutfly/p/11586472.html
Copyright © 2020-2023  润新知