Fun论设计模式之2:代理模式(Proxy Pattern)

2023-11-18

  今天学习到了一个新的设计模式:代理模式。介绍借鉴了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个模块整合起来代理,这样优化级别就是模块等级了。

转载于:https://www.cnblogs.com/dgutfly/p/11586472.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Fun论设计模式之2:代理模式(Proxy Pattern) 的相关文章

  • 为什么byteArray的长度是22而不是20?

    我们尝试从字符串转换为Byte 使用以下 Java 代码 String source 0123456789 byte byteArray source getBytes UTF 16 我们得到一个长度为 22 字节的字节数组 我们不确定这个
  • 如何将对象从 rake 任务传递给 Rabl 视图

    我正在尝试使用 rabl 从 rake 任务创建 json 文件 下面我有一个简化版本来测试 当我通过 url 查看 articles json 或 articles 2 json 时 我得到了预期的 json 响应 但是当我尝试通过 ra
  • 具有最小刻度的图表的漂亮标签算法

    我需要手动计算图表的刻度标签和刻度范围 我知道漂亮刻度的 标准 算法 参见 我也知道这个Java实现 http erison blogspot nl 2011 07 algorithm for optimal scaling on char
  • 使用 Hibernate 和 Apache DBCP 的 MySQL 连接池问题

    看来我的应用程序有问题 当应用程序在启动后闲置很长时间 我不确定确切的时间 时 我会在日志中收到以下错误消息 我使用 Spring Hibernate MySQL 和 ApacheDBCP 进行连接池 ERROR org hibernate
  • JFreeChart - 创建移动图表时出现问题

    我在我的 java 应用程序中使用 JFreeChart Problem 我想绘制一个XY面积图 whose 域轴 x 轴 当我们开始绘制数据时应该自动水平滚动 我在中看到了同样的事情时间序列图表但我不想要任何时间系列图表 我只想要滚动的
  • 到底什么是哈希冲突

    HashMap 中的哈希冲突或哈希冲突并不是一个新主题 我遇到过几个博客和讨论板 以模糊且详细的方式解释如何产生哈希冲突或如何避免它 我最近在一次采访中遇到了这个问题 我有很多事情要解释 但我认为很难准确地给出正确的解释 抱歉 如果我的问题
  • Bug 组合:jQuery 1.4、ajax/json、Firebug Lite 和 IE 8

    我刚刚得出结论 无论我如何尝试 jQuery 的 ajax 调用都无法在 IE 8 中处理 JSON 数据 我发现我可以使用 jQuery 1 3 2 库 这解决了问题 但 1 4 根本无法处理 JSON ajax 请求 即使返回的 JSO
  • @Cachable 在没有输入参数的方法上?

    我有问题 org springframework cache annotation Cachable注解 Bean public ConcurrentMapCache cache return new ConcurrentMapCache
  • 解密 TLS 1.2 AES-GCM 数据包

    我正在开发一个 Java 程序来解密TLS 1 2正在使用的会话TLS RSA WITH AES 128 GCM SHA256密码 我使用wireshark 录制了一个测试会话 这大师秘密是已知的 No Time Protocol Leng
  • 整数与 int 比较

    我是新来的java 我现在正在学习非原始整数类型java 我知道以下比较无效并引发编译错误 String str c Char chr c if str chr return true 上面的代码片段给了我 Test java lineNu
  • java:如何设置全局线程ID?

    是否有可能为线程设置唯一ID 在分布式系统中 线程是在许多不同的机器上创建的 例如通过 RMI 我需要它来创建日志消息 根据我的研究 我知道可以使用 log4j mdc ndc 来完成 但只能在单线程中完成 我的问题是 在创建线程时必须设置
  • 如何使用键盘上的“删除”按钮作为从 JTable 中删除行的快捷方式[重复]

    这个问题在这里已经有答案了 可能的重复 如何制作删除按钮来删除JTable中的行 https stackoverflow com questions 13236206 how to make delete button to delete
  • 将 XML 从网站解析到 Android 设备

    我正在启动一个 Android 应用程序 它将解析来自网络的 XML 我创建了一些 Android 应用程序 但它们从未涉及解析 XML 我想知道是否有人对最佳方法有任何建议 这是一个例子 try URL url new URL your
  • logcat 信息出现在 Android Studio 的“运行”选项卡中

    我的 android studio 运行选项卡很简单 然后它变得更难并给我更多信息 例如 logcat 中的信息 如何禁用或删除第二张图片中出现的更多信息并返回到第一张图片中的第一个外观 我只需要正在运行的 flutter 应用程序的日志输
  • Eclipse 在单独的窗口中打开代码

    我正在 eclipse 中编程 在两个显示器设置上运行 在其中一台显示器上 我只获得了项目资源管理器和编辑器作为自定义透视图 而在另一台显示器上 我获得了其他工具 例如控制台 调试 任务 变量 断点等 例如 当我单击任务视图中的任务时 这将
  • 找出该月第一个星期日/星期一等的日期

    我想在java中检测每个月第一周 第二周的第一个星期日 星期一的日期 我怎样才能实现它 我已经检查了 java 中的 Calendar 类和 Date 类 但无法找到解决方案 所以请帮助我解决这个问题 Calendar calendar C
  • 从数字列表中生成所有唯一对,n 选择 2

    我有一个元素列表 假设是整数 我需要进行所有可能的两对比较 我的方法是 O n 2 我想知道是否有更快的方法 这是我在java中的实现 public class Pair public int x y public Pair int x i
  • 如何从 jenkins 的现有项目生成 .hpi 插件

    我正在尝试使用 jenkins 的性能插件 但最新版本存在一些问题 如链接中所述 https issues jenkins ci org browse JENKINS 27100 https issues jenkins ci org br
  • 在java中打印阿拉伯字符串

    我试图在 java 中显示阿拉伯语文本 但它显示垃圾字符 示例 或有时在我打印时仅显示问号 我如何才能打印阿拉伯语 我听说它与unicode和UTF 8有关 这是我第一次使用语言 所以不知道 我正在使用 Eclipse Indigo IDE
  • 如何将 JSON 文本转换为 PHP 关联数组

    我将以下 JSON 对象存储在文本文件 data txt 中 player black time 0 from 2c to 3d 我使用 php 阅读 问题 有没有简单的方法可以转换 data到 PHP 关联数组 我尝试过使用json de

随机推荐

  • 通过wiki进行企业内部的知识共享

    其实企业内部的知识共享是一个很复杂的问题 每个人都有自己的经验和Key Knowledge 每次开发也能积累到很多有用的开发经验或者教训 可是怎样才能进行有效的知识共享呢 一个完善的知识共享系统应该具有以下几种特性 易于使用的界面 好的知识
  • 突如其来的C#重新学习(2)

    突如其来的C 重新学习 2 关于Main入口点的问题 Main在C 中不能单独声明 所以必须声明在同一个类中 而且必须声明静态方法 返回可以是void或者int 正常执行应当返回0 对于一个命名空间之内有很多的类的情况下 就可以手动选择从哪
  • 前端网页设置视频背景

    视频设置自动播放 循环播放 静音 一定要设置静音不设置静音的话不会自动播放 video元素设置width 100 height auto 如果height设置100 的话 定位之后会看不到
  • pycharm常用快捷键及快捷键自定义修改

    一 常用快捷键 编辑类 Ctrl D 复制选定的区域或行 Ctrl Y 删除选定的行 Ctrl Alt L 代码格式化 Ctrl Alt O 优化导入 去掉用不到的包导入 Ctrl 鼠标 简介 进入代码定义 Ctrl 行注释 取消注释 Ct
  • 关闭WIN10的wsappx进程服务

    关闭原因 打开电脑登录系统后 发现wsappx进程服务占用CPU极高 并且一直没有降低 如下图所示 解决办法 将以下注册表的值由3修改为4重启系统即可 计算机 HKEY LOCAL MACHINE SYSTEM CurrentControl
  • 手把手帮助你通过Vue+Springboot+MybatisPlus实现一个简单的登录注册页面,0基础

    创建前端vue项目 首先通过脚手架创建vue文件夹 前提 安装好node js软件 安装好后 通过node V 查看版本号 npm V查看npm版本 通过命令安装脚手架 npm install g vue cli g代表全局安装 s代表本地
  • 浅谈Nginx相关HTTP杂项模块(一)

    浅谈Nginx相关HTTP杂项模块 一 1 ngx http access module 2 ngx http auth basic module 3 ngx http stub status module 4 ngx http log m
  • 拷贝本地文件到docker容器

    查找所有容器 docker ps a 找出我们想要的容器名字 查找容器长ID docker inspect f ID python 拷贝本地文件到容器 docker cp 本地路径 容器长ID 容器路径 docker cp Users xu
  • c++ 打印当前时间(精确到毫秒)

    打印时间精确到毫秒好实现 但是那种对用户可读性不好 更适合开头记一次结尾记一次 打印中间减出来的程序运行时间 但是因为一些情况 我开多线程开的不方便打印结束时间 同事跟我说那你把开始时间打印一下 结束他自己接受那边打印 最好精确到毫秒 那就
  • (电赛电源方向)怎么样从零开始准备全国大学生电子设计竞赛

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 电赛是什么 二 电源方向是什么 三 该怎么去学习电源方向的知识 1 博主的劝诫 2 硬件该准备些什么 3 软件该准备些什么 总结 前言 我建了一个群 分享
  • selenium 常用操作总结

    谷歌驱动下载 http chromedriver storage googleapis com index html 参数设置options opt Options opt add argument headless 无头模式 opt ad
  • 在腾讯连拿六个五星

    刚毕业入职腾讯工作 2 3 年 半年 年终绩效每次都是 5 4 星 不一定年薪百万 主要薪资 奖金无法决定 这个取决于股票是否上涨不少 但晋升肯定是最快的 在阿里拿 375 跟在腾讯拿 5 4 星的比例差不多 应届毕业能拿一次确实很优秀了
  • 15. unity官网资源商店的免费资源引入自己项目中

    1 说明 在unity开发中可以在官网引入一些免费的资源 免得自己找不到合适的素材 第一步 首先进入Unity资源商店官网 https assetstore unity com 计入并登录自己的unity账号 如果没账号 可以注册一个 然后
  • Fisco Bcos区块链五(WeBase结点前置服务)

    文章目录 区块链开荒 技术文档 https webasedoc readthedocs io zh CN latest docs WeBASE Front install html 三 WeBase节点前置服务 1 前提条件 2 拉取代码
  • AIGC驱动产品开发创新,改变你所知的一切!

    你是否想过 3000年后的饮料是什么味道 9月12日 可口可乐全球创意平台 乐创无界 再度推出全新限定产品 首款联合人工智能 AI 打造的无糖可口可乐 未来3000年 从口味研发到包装设计都体现了AI的深度参与打造 Y3000与AI共创这一
  • 实战: 跨年烟花代码的实现(附源码)

    目录 前言 一 pandas是什么 二 代码结构 1 介绍主html代码 2 js文件介绍 GameCanvas js script js 运行效果 前言 本文章将介绍跨年烟花代码的实现以及源代码 提示 以下是本篇文章正文内容 一 pand
  • 关于security权限的坑

    遇到了一个spring security的坑 分享给大家 首先介绍一下项目 spring boot 整合security 配合做权限与认证 如果数据库权限是ROLE USER 比如 那么在Security配置文件里 权限必须写出USER 也
  • 如何在vue 中使用 sass

    传送门
  • python中协程实现的本质以及两个封装协程模块greenle、gevent

    协程 协程 又称微线程 纤程 英文名Coroutine 协程是啥 协程是python个中另外一种实现多任务的方式 只不过比线程更小占用更小执行单元 理解为需要的资源 为啥说它是一个执行单元 因为它自带CPU上下文 这样只要在合适的时机 我们
  • Fun论设计模式之2:代理模式(Proxy Pattern)

    今天学习到了一个新的设计模式 代理模式 介绍借鉴了runoob的 意图 为其他对象提供一种代理以控制对这个对象的访问 主要解决 在直接访问对象时带来的问题 比如说 要访问的对象在远程的机器上 在面向对象系统中 有些对象由于某些原因 比如对象