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的依赖注入内部不止要做代理,还要维护工厂生产的组件)

posted @ 2019-09-28 13:35  DGUT_FLY  阅读(425)  评论(0编辑  收藏  举报