代理模式应该是Spring核心设计模式之一了
先说下代理模式特性:
1.有代理人和被代理人
2.对于被代理的人来说,这件事情是一定要做的,但是我又不想做,所有就找代理人来做。
3.需要获取到被代理人的个人资料。
Spring中的代理模式是声明式事务 (AOP)
代理模式代码中的使用
1.日志监听
2.开启,关闭事务
3.等等
现实中的例子:
黄牛:我需要买票又不想排队,黄牛拿着我的个人信息代替我买票。。emmmmm不合法,但确实是代理模式
相亲: 我需要女朋友又不主动找女朋友,所以媒婆拿着我的个人条件,代替我去找女朋友??????总感觉哪里怪怪的
GitHub源码地址:https://github.com/wujiachengSH/WjcProxyDemo
下面我们来举个栗子看下代码中的代理是什么样子的
咳咳,来个找对象吧
先定义个接口
package com.wjc.proxy; public interface People { String getHeight(); String getSex(); //择偶标准
void getStandardsOfChoosingSpouse(); }
来个实现类
package com.wjc.proxy; public class Wjc implements People { private String height = "170";
private String Sex = "男"; @Override
public String getHeight() {
// TODO Auto-generated method stub
return height;
} @Override
public String getSex() {
// TODO Auto-generated method stub
return Sex;
} @Override
public void getStandardsOfChoosingSpouse() {
// TODO Auto-generated method stub
System.out.println("性别男,爱好女");
System.out.println("不想努力了,求富婆包养"); } }
来个代理类,代替我调用我自己,传说中的害羞。。噗
package com.wjc.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class MatchMaker implements InvocationHandler {
// 拿到被代理的对象
private People target; // 获取被代理对象
public Object getInstance(People target) throws Exception {
this.target = target;
Class clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-------这是一位"+this.target.getSex()+"性-------"); method.invoke(this.target, args);
System.out.println("找富婆是要付出代价的"); return null;
} }
测试一下
package com.wjc.proxy; public class Test {
public static void main(String[] args) { try {
People instance = (People) new MatchMaker().getInstance(new Wjc());
instance.getStandardsOfChoosingSpouse(); instance.getHeight();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}
测试结果
通过这个简单的栗子,看到所谓的代理,其实就是方法增强,嗯,可以拿到对象的所有方法,并且以一定顺序来执行。
那么问题就来了,到底是怎么实现的呢?
package com.wjc.proxy; public class Test2 {
public static void main(String[] args) { try {
Wjc wjc = new Wjc();
People instance = (People) new MatchMaker().getInstance(wjc);
System.out.println(wjc.getClass());
System.out.println(instance.getClass()); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}
执行结果
可以看到已经不是原来的类了
在代理的过程中,会使用反射的技巧,重新生成一个类!
大致代理流程如下所示
//1.拿到被代理对象的引用,然后获取它的接口
//2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
//3.把被代理对象的引用也拿到了
//4.重新动态生成一个class字节码
//5.然后编译
我们将打印并反编译出来,看看到底都干啥了
打印类方法
byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
FileOutputStream os = new FileOutputStream("E:/$Proxy0.class");
os.write(data);
os.close();
通过小工具(luyten) 下载地址:https://github.com/deathmarine/Luyten/releases/tag/v0.5.4
可以看到,创建的类获取了对象的hashcode,equals,toString和其自有方法来创建了一个新类
所有在使用代理时,此类就是代理人,被他反射的方法的对象就是被代理人
import com.wjc.proxy.*;
import java.lang.reflect.*; public final class $Proxy0 extends Proxy implements People
{
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m0; public $Proxy0(final InvocationHandler invocationHandler) {
super(invocationHandler);
} public final boolean equals(final Object o) {
try {
return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} public final String getSex() {
try {
return (String)super.h.invoke(this, $Proxy0.m4, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} public final String toString() {
try {
return (String)super.h.invoke(this, $Proxy0.m2, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} public final void getStandardsOfChoosingSpouse() {
try {
super.h.invoke(this, $Proxy0.m3, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} public final String getHeight() {
try {
return (String)super.h.invoke(this, $Proxy0.m5, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} public final int hashCode() {
try {
return (int)super.h.invoke(this, $Proxy0.m0, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
} static {
try {
$Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$Proxy0.m4 = Class.forName("com.wjc.proxy.People").getMethod("getSex", (Class<?>[])new Class[0]);
$Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
$Proxy0.m3 = Class.forName("com.wjc.proxy.People").getMethod("getStandardsOfChoosingSpouse", (Class<?>[])new Class[0]);
$Proxy0.m5 = Class.forName("com.wjc.proxy.People").getMethod("getHeight", (Class<?>[])new Class[0]);
$Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
}
catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
catch (ClassNotFoundException ex2) {
throw new NoClassDefFoundError(ex2.getMessage());
}
}
}