代理 、动态代理 笔记

代理 、动态代理

代理概念:

中介,即为单或多个服务类对象提供一种服务以控制其他类对该对象的访问。

在某些情况下,一个对象不适合或不能直接引用另一个对象,代理对象可以在请求类和目标类之间起到中介的作用。
代理模式:
代理模式是一种设计模式

jdk: reflect

代理的作用:

1。功能增强
在执行目标类的功能的同时可以进行
2。访问控制
控制访问类是否能访问目标类。

代理:
接口: SellingFigure.interface
接口实现类:厂商 .java implement SellingFigure

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270


//静态代理类:
package StaticProxy;

public class bilibiliProxy implements SellFigure {
private SellFigure s;

public bilibiliProxy(SellFigure s) {
this.s = s;
}

public int SellingFigure(String buyerName) {
int oprice=s.SellingFigure(buyerName);
double sprice= oprice+(oprice*0.25);
System.out.println("您通过bilibili购买:");
return (int) sprice;

}
}

//接口类(销售行为)
package StaticProxy;

public interface SellFigure {
public int SellingFigure(String proxyname);
}


//接口实现类(厂家)
package StaticProxy;

public class SellingImpl implements SellFigure {
public SellingImpl() {
}

public int SellingFigure(String proxyname) {
System.out.println("此为目标实现类的目标方法。 static way");
int price;
if(proxyname.equals("bilibili"))
price=980;
else if(proxyname.equals("acfun"))
price=680;
else
price=900;
return price;
}
}

//staticReflect.properties

Typo=bilibili
methodName=SellingFigure
implName=SellingImpl
name=SellFigure


//测试类:


package StaticProxy;

import org.junit.Test;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

//not proxy using
public class otakuTest {
@Test
//不使用代理直接获取。
public void test1(){
SellFigure s = new SellingImpl();
System.out.println("死宅1号买入价格:"+ s.SellingFigure("myself") );

}
@Test
//使用反射与配置文件调用bilibiliProxy的方法代理
public void test2() throws Exception{
//1. read properties by classloader and properties.class
ClassLoader clz=otakuTest.class.getClassLoader();
InputStream clzs = clz.getSystemResourceAsStream("staticReflect.properties");
Properties pro = new Properties();
pro.load(clzs);
//2. get property in properties file.
String typo = pro.getProperty("Typo");
String methodname = pro.getProperty("methodName");
String classname ="staticProxy."+typo+"Proxy";
String implename = "staticProxy."+pro.getProperty("implName");
//3. load the .class into RAM for a class object
Class clazz = Class.forName(classname);
Class implclazz = Class.forName(implename);
//4. create the instance and get the method
Object obj = clazz.getConstructor(SellFigure.class).newInstance(implclazz.newInstance());
Method met = clazz.getDeclaredMethod(methodname,String.class);
//5. setAccessible to true for the hidden private method and fields.
met.setAccessible(true);
//6. using the method.class 's method invoke to execute the method as a object file.
Object a = met.invoke(obj,typo);

System.out.println(a);


//
// SellFigure s = new bilibiliProxy(new SellingImpl());
// System.out.println("死宅2号买入价格:"+ s.SellingFigure("bilibili") );
}
@Test
//静态代理 使用acfun代理购买。
public void test3(){
SellFigure s = new acfunProxy(new SellingImpl());
System.out.println("死宅3号买入价格:"+ s.SellingFigure("acfun") );
}



}



//动态代理:
1.jdk
//代理辅助类
package Dynamicproxy.jdks;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DbilibiliProxy implements InvocationHandler {


public DbilibiliProxy(Object target) {
this.target = target;
}

private Object target;

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("通过辅助代理bilibili");
//代理执行方法
Object res = method.invoke(target,args);
//功能增强
if(res!=null){
Integer price=(Integer) res;
price=(int)(price*1.25);
res=price;
}
return res;

}
}
//实现类与接口同静态。

//客户测试类
package Dynamicproxy.jdks;

import java.io.InputStream;
import java.util.Properties;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

//using dynamic proxy
public class otaku {
public static void main(String[] args) throws Exception {
//1. read properties by classloader and properties.class
ClassLoader clz = otaku.class.getClassLoader();
InputStream clzs = clz.getSystemResourceAsStream("staticReflect.properties");
Properties pro = new Properties();
pro.load(clzs);
//2. get property in properties file.
String typo = pro.getProperty("Typo");
String interfaceName = pro.getProperty("name");
String proxyName = "dynamicproxy.jdks." + "D" + typo + "Proxy";
interfaceName = "dynamicproxy.jdks." + interfaceName;
String implename = "dynamicproxy.jdks." + pro.getProperty("implName");
InvocationHandler proxyhandler = (InvocationHandler) Class.forName(proxyName).getConstructor(Object.class).newInstance(Class.forName(implename).newInstance());
SellFigure dynamicWay = (SellFigure) Proxy.newProxyInstance(Class.forName(interfaceName).getClassLoader(), Class.forName(implename).getInterfaces(), proxyhandler);
System.out.println(dynamicWay.SellingFigure(typo));
}
}


2.cglib代理

//代理辅助类:

package Dynamicproxy.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

//代理创建器
public class DynamicCglibProxy implements MethodInterceptor {

private Enhancer enhancer = new Enhancer();
private Object target;

public DynamicCglibProxy(Object obj) {
target = obj;
}
public Object getProxy(){
//设置需要代理的父类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//动态创建子类实例
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("通过动态代理实现");
Object result = method.invoke(target, objects);
System.out.println("由cglib代理出售了!");
int t = (int) ((Integer)result *1.25);
result=t;
return result;
}
}



//被代理类
package Dynamicproxy.cglib;


public class Selling {
int price;
//
// public int SellingFigureTobilibili(String proxyname) {
// price=980;
// return price;
// }

public int SellingFigure(String proxyname) {
System.out.println("此为目标实现类的目标方法。dynamic way ");

if(proxyname.equals("bilibili"))
price=980;
else if(proxyname.equals("acfun"))
price=680;
else
price=900;
return price;
}

// public int SellingFigureToacfun(String proxyname) {
// price=680;
// return price;
// }

}

//测试类

package Dynamicproxy.cglib;

//客户端类
public class otaku {
public static void main(String[] args) {
Selling Sellfigure = new Selling();
DynamicCglibProxy dynamicCglibProxy = new DynamicCglibProxy(Sellfigure);
Selling sellProxy = (Selling) dynamicCglibProxy.getProxy();
System.out.println(sellProxy.SellingFigure("bilibili"));;
}
}

动态代理分两类
jdk自带的动态代理reflect Proxy
和cglib第三方类,分别的实现原理是反射、ASM(字节码编译)。
反射速率会差上一大截。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//测试结果
//创建代理的速度
Create JDK Proxy: 13 ms
Create CGLIB Proxy: 217 ms //较慢
Create JAVAASSIST Proxy: 99 ms
Create JAVAASSIST Bytecode Proxy: 168 ms //较慢
Create ASM Proxy: 3 ms //最快

================
Run JDK Proxy: 2224 ms, 634,022 t/s //很慢,jdk生成的字节码考虑了太多的条件,所以字节码非常多,大多都是用不到的
Run CGLIB Proxy: 1123 ms, 1,255,623 t/s //较慢,也是因为字节码稍微多了点
Run JAVAASSIST Proxy: 3212 ms, 438,999 t/s //非常慢,完全不建议使用javassist的代理类来实现动态代理
Run JAVAASSIST Bytecode Proxy: 206 ms, 6,844,977 t/s //和asm差不多的执行速度,因为他们都是只生成简单纯粹的执行字节码,非常少(所以直接用javassist生成代理类的方式最值得推荐[从速度上讲])
Run ASM Bytecode Proxy: 209 ms, 6,746,724 t/s //asm什么都是最快的,毕竟是只和最底层打交道

评论