一般来说最常见的动态代理是这么写的:
1,正常版本
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy implements InvocationHandler {
private Object target;
public Object getInstance(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDProxy execute before...");
Object result = method.invoke(target,args);
System.out.println("JDProxy execute after...");
return result;
}
}
2,改进版本
public class ProxyFactory {
public static Object getProxyInstance(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* System.out.println(proxy);
System.out.println(method);
System.out.println(args);*/
System.out.println(“日志记录begin”);
Object result = method.invoke(target, args);
System.out.println(“日志记录end”);
return result;
}
});
}
}
首先跟一下Proxy.newProxyInstance
System.out.println(sonProxy.getClass());
class com.sun.proxy. P r o x y 0 代 理 类 的 c l a s s 为 Proxy0 代理类的class为 Proxy0代理类的class为Proxy,就是意味着 Proxy.newProxyInstance的功能就是产生一个 P r o x y , 而 Proxy,而 Proxy,而Proxy是什么呢?有一个骚操作
通过反编译工具查看class的源码
byte[]
P
r
o
x
y
0
s
=
P
r
o
x
y
G
e
n
e
r
a
t
o
r
.
g
e
n
e
r
a
t
e
P
r
o
x
y
C
l
a
s
s
(
"
Proxy0s = ProxyGenerator.generateProxyClass("
Proxy0s=ProxyGenerator.generateProxyClass("Proxy0", new Class[]{Person.class});
FileOutputStream fileOutputStream = new FileOutputStream("E://
P
r
o
x
y
123.
c
l
a
s
s
"
)
;
f
i
l
e
O
u
t
p
u
t
S
t
r
e
a
m
.
w
r
i
t
e
(
Proxy123.class"); fileOutputStream.write(
Proxy123.class");fileOutputStream.write(Proxy0s);
fileOutputStream.flush();
fileOutputStream.close();
然后把 $Proxy123.class放到idea里面就能看到内容:
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void findLove() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.huffman.pattern.proxy.dynamic_jdk.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看出来 Proxy.newProxyInstance具体做的就是生成一个代理类$Proxy,代理类里面克隆了当前类所有方法,而且调用findxxx()方法时其实是调用在定义InvocationHandler.invoke()定义的方法;
所以我们的手写动态代理的思路为:
1,直接生成$proxy.java
2,把 p r o x y . j a v a 编 译 成 proxy.java编译成 proxy.java编译成proxy.class
3,用类加载器把$proxy.class生成class实例
4,把class实例返回代理对象
所以重写Proxy的newProxyInstance用代码实现为:
public static Object newProxyInstance(MyClassLoader classLoader,Class<?>[] interfaces,MyInvocationHandler myInvocationHandler) throws IllegalArgumentException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.动态生成java文件源码
String src=generateSrc(interfaces);
//2.将java源码生成本地文件
String classPath = MyProxy.class.getResource("").getPath();
File file = new File(classPath + “
P
r
o
x
y
0.
j
a
v
a
"
)
;
F
i
l
e
W
r
i
t
e
r
f
i
l
e
W
r
i
t
e
r
=
n
e
w
F
i
l
e
W
r
i
t
e
r
(
f
i
l
e
)
;
f
i
l
e
W
r
i
t
e
r
.
w
r
i
t
e
(
s
r
c
)
;
f
i
l
e
W
r
i
t
e
r
.
f
l
u
s
h
(
)
;
f
i
l
e
W
r
i
t
e
r
.
c
l
o
s
e
(
)
;
/
/
3.
动
态
编
译
j
a
v
a
源
码
,
生
成
c
l
a
s
s
文
件
J
a
v
a
C
o
m
p
i
l
e
r
c
o
m
p
i
l
e
r
=
T
o
o
l
P
r
o
v
i
d
e
r
.
g
e
t
S
y
s
t
e
m
J
a
v
a
C
o
m
p
i
l
e
r
(
)
;
S
t
a
n
d
a
r
d
J
a
v
a
F
i
l
e
M
a
n
a
g
e
r
m
a
n
a
g
e
=
c
o
m
p
i
l
e
r
.
g
e
t
S
t
a
n
d
a
r
d
F
i
l
e
M
a
n
a
g
e
r
(
n
u
l
l
,
n
u
l
l
,
n
u
l
l
)
;
I
t
e
r
a
b
l
e
i
t
e
r
a
b
l
e
=
m
a
n
a
g
e
.
g
e
t
J
a
v
a
F
i
l
e
O
b
j
e
c
t
s
(
f
i
l
e
)
;
J
a
v
a
C
o
m
p
i
l
e
r
.
C
o
m
p
i
l
a
t
i
o
n
T
a
s
k
t
a
s
k
=
c
o
m
p
i
l
e
r
.
g
e
t
T
a
s
k
(
n
u
l
l
,
m
a
n
a
g
e
,
n
u
l
l
,
n
u
l
l
,
n
u
l
l
,
i
t
e
r
a
b
l
e
)
;
t
a
s
k
.
c
a
l
l
(
)
;
m
a
n
a
g
e
.
c
l
o
s
e
(
)
;
/
/
4.
加
载
c
l
a
s
s
文
件
生
成
C
l
a
s
s
实
例
C
l
a
s
s
p
r
o
x
y
C
l
a
s
s
=
c
l
a
s
s
L
o
a
d
e
r
.
f
i
n
d
C
l
a
s
s
(
"
Proxy0.java"); FileWriter fileWriter = new FileWriter(file); fileWriter.write(src); fileWriter.flush(); fileWriter.close(); //3.动态编译java源码,生成class文件 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null); Iterable iterable = manage.getJavaFileObjects(file); JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable); task.call(); manage.close(); //4.加载class文件生成Class实例 Class proxyClass = classLoader.findClass("
Proxy0.java");FileWriterfileWriter=newFileWriter(file);fileWriter.write(src);fileWriter.flush();fileWriter.close();//3.动态编译java源码,生成class文件JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();StandardJavaFileManagermanage=compiler.getStandardFileManager(null,null,null);Iterableiterable=manage.getJavaFileObjects(file);JavaCompiler.CompilationTasktask=compiler.getTask(null,manage,null,null,null,iterable);task.call();manage.close();//4.加载class文件生成Class实例ClassproxyClass=classLoader.findClass("Proxy0”);
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
// file.delete();
//5.根据类型Class生成代理对象
return c.newInstance(myInvocationHandler);
}
自定义类加载器就是把本地生成的$Proxy0.class加载到jvm
public class MyClassLoader extends ClassLoader {
private File classPathFile;
public MyClassLoader(){
String classPath = MyClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
if(classFile.exists()){
FileInputStream in = null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if(null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
至此,手动实现动态代理就完成了;
博客介绍了Java动态代理常见写法,包括正常版本和改进版本。通过反编译工具查看代理类源码,分析了Proxy.newProxyInstance的功能。还阐述了手写动态代理的思路,即生成Java文件、编译成class文件、用类加载器生成实例并返回代理对象,最后给出了代码实现。
491

被折叠的 条评论
为什么被折叠?



