目录
1 概述
定义:为其他对象提供一种代理以控制对这个对象的访问
实例:王二狗公司(天津在线回声科技发展有限公司)老板突然在发工资的前一天带着小姨子跑路了,可怜二狗一身房贷,被迫提起劳动仲裁,劳动局就会为其指派一位代理律师全权负责二狗的仲裁事宜。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理王二狗。
某人要找对象,但是由于某些原因(如工作太忙)不能直接去找,于是委托一个中介机构去完成这一过程,如婚姻介绍所,在这里婚姻介绍所就是一个代理,与此相类似的还有房屋中介、职业中介,它们充当的都是一个代理的角色。所谓代理,就是一个人或者一个机构代表另一个或者另一个机构采取行动。在我们所开发的软件系统中有时候也存在这样的情况,如调用一个远程的方法,需要在本地设置一个代理,使得就像调用本地方法一样来使用远程的方法,这实际上也就是RMI、WebService等的实现原理。
在某些情况下,一个客户不想或不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
如在网页上查看一张图片,由于网速等原因图片不能立即显示,可以在图片传输过程中先把一些简单的用于描述图片的文字(或者小图片)传输到客户端,此时这些文字(或小图片)就成为了图片的代理。
2 代理模式结构
Subject是顶层接口,RealSubject是真实对象,Proxy是代理对象,代理对象持有被代理对象的引用,客户端调用代理对象的方法,同时也调用被代理对象的方法,但是在代理对象前后增加一些处理。在代码中,我们想到代理,就会理解为是代码的增强,其实就是在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构性模式,有静态代理和动态代理。
-
Subject类,定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy
-
RealSubject类(被代理对象),定义Proxy所代表的真实实体
-
Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体
代理模式示意结构图比较简单,一般可以简化为如下图所示,但是在现实中要复杂很多。
主要代码如下:
public class Proxy implements Subject
{
private RealSubject realSubject = new RealSubject();
public void preRequest()
{…...}
public void request()
{
preRequest();
realSubject.request();
postRequest();
}
public void postRequest()
{……}
}
3 静态代理(接口代理)
需求(干什么):对明星唱歌的业务流程进行代理,而明星唱歌还是交由明星自己唱歌,这个流程把唱歌分成2部分了,1:歌手尽管唱歌,2:代理公司负责打杂(面谈,签合同,订票,收钱),对被代理的歌手来说,他解放了,相当于增强了,不用自己面谈,签合同什么的,对代理公司来说,我就打杂就行了,赚点差价,唱歌不行,只好请歌手(无法全程代理),各司其职.
先明确所有流程下来需要干那些事情,使用接口明确一下(面向接口编程哈)
package com.demo.proxy.staticproxy;
/**
* Star:代理接口,这里规定了整个业务需要完成的事情
* (万事万物接口开头,面向接口编程,先明确要干什么,怎么干是后面实现类的事情,这样有利于解耦,
* 比如同样是面谈的实现,需要换个面谈方式那不是还得修改代理类?这里直接定义成接口,那么代理要换个代理只需要换个代理实现类就行了
* 不需要对代理接口进行修改,达到开闭原则,开放拓展,但是修改接口这个代理接口Star不允许)
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
知道了要干什么(上面接口明确了),但是怎么干(实现类)呢,先来个歌手独立开一场演唱会就需要实现所有接口,又当爹又当妈
//package com.demo.proxy.staticproxy;
/**
* RealStar:一个真实的歌手,在没有代理的情况下需要全部实现,又当爹又当妈
* (显然不不合理,对歌手来说,除了唱歌,其他打杂的事情,面谈,签合同什么的都没有必要去做)
*
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class RealStar implements Star {
/**
* 面谈
*/
@Override
public void confer() {
//可以做空实现
System.out.println("真实对象执行面谈===>RealStar.confer()");
}
/**
* 签合同
*/
@Override
public void signContract() {
//可以做空实现
System.out.println("真实对象执行签合同===>RealStar.confer()");
}
/**
* 订票
*/
@Override
public void bookTicket() {
//可以做空实现
System.out.println("真实对象执行订票===>RealStar.confer()");
}
/**
* 唱歌---歌手主要唱歌,其他事情(具体实现),可以不做(就是空实现)
*/
@Override
public void sing() {
//这里唱歌是必须实现的,不然算什么歌手
System.out.println("真实对象(周杰伦)执行唱歌===>RealStar.confer()");
}
/**
* 收钱
*/
@Override
public void collectMoney() {
//可以做空实现
System.out.println("真实对象执行收钱===>RealStar.confer()");
}
}
上面真实歌手在吐槽又当爹又当妈,我作为天使,肯定是来解救你的,并且我不抢你唱歌的光彩,你唱你的,我给你打杂就行了,赚点差价哈哈,下面就是我的自我介绍
//package com.demo.proxy.staticproxy;
/**
* ProxyStar:代理对象,这是个对某个类(对象)进行增强的
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class ProxyStar implements Star {
/**
* 专业的事情教给专业的人去做,比如在这里就是相当于请歌手唱歌
* 注意这里接口做属性,组合比实现类(应用)做属性好的多,因为接口做属性可以请很多歌手唱歌(提现多态),
* 但是是实现类做属性(面向实现编程)耦合度太高,换个歌手又得修改这个类,开闭原则是尽量不要修改这个类,所以这里
* 是使用Star,而不是 private RealStar star
* ---静态代理代理的是接口就是出自这里
*/
private Star star;
/**
* 怎么请?这里使用构造方法请,用set方法也行
* @param star
*/
public ProxyStar(Star star) {
this.star = star;
}
/**
* 面谈---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void confer() {
System.out.println("代理面谈===>ProxyStar.bookTicket()");
}
/**
* 签合同---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void signContract() {
System.out.println("代理签合同===>ProxyStar.bookTicket()");
}
/**
* 订票---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void bookTicket() {
System.out.println("代理订票===>ProxyStar.bookTicket()");
}
/**
* 唱歌===专业的人做专业的事
*/
@Override
public void sing() {
System.out.println("*******代理对象不抢主角光环*******");
star.sing();
}
/**
* 收钱---代理对象专业的人处理其他事情,相当于打杂,对专业的人来说,相当于增强了
*/
@Override
public void collectMoney() {
System.out.println("代理收钱===>ProxyStar.bookTicket()");
}
}
牛皮都吹出去了,测试一下呗,合作愉快下次继续哟,亲,记得给个五星好评哟
package com.demo.proxy.staticproxy;
/**
* Client:客户端 静态代理测试
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class Client {
public static void main(String[] args) {
System.out.println("----------------------测试静态代理-------------------");
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer();
proxy.signContract();
proxy.bookTicket();
//这里代理对象持有真实对象的一切,比如让代理的真实对象周杰伦唱歌,对周杰伦这个对象来说,他功能增强了,
//上面的操作和下面的操作都算增强
proxy.sing();
proxy.collectMoney();
}
}
演唱会全程回顾如下:
4 动态代理(代理对象)
动态代理是指在运行时,动态生成代理类。即,代理类的字节码将在运行时生成并载入当前的ClassLoader。与静态代理类想比,动态类有诸多好处。首先,不需要为真是主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也是非常烦人的事,如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;其次,使用一些动态代理的生成方法甚至可以在运行时指定代理类的执行逻辑,从而大大提升系统的灵活性。
在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
InvocationHandler
接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy
是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。
Star接口还是那个接口(上文静态代理的),RealStar接口还是那个接口(上文静态代理的)
//package com.demo.proxy.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* StarHandler:这是一个对JDK调用处理器的实现类,用于被代理的一个类,利用这个类可以JDK为其生成一个代理对象
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class StarHandler implements InvocationHandler {
/**
* 这里仍然是要代理接口的,相当于唱歌业务流程始终是要有公司接单,实现演唱会,只是这里不是代理类直接接单
* 由评审团StarHandler来评估先代理
*/
Star realStar;
/**
* 构造方法注入"演唱会订单"
* @param realStar
*/
public StarHandler(Star realStar) {
this.realStar = realStar;
}
/**
* 重写JDK代理方法(使用反射生成响应对象)
* @param proxy 评估后具备代理资格的代理公司对象
* @param method 方法(真是对象需要执行的操作,唱歌)
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 评估后具备代理资格的代理公司对象
Object object = null;
System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票");
//用反射的方式获取方法名称
if(method.getName().equals("sing")){
object = method.invoke(realStar, args);
}
System.out.println("真正的方法执行后!");
System.out.println("收尾款");
return object;
}
}
模拟动态生成的代理的类
//package com.demo.proxy.dynamicproxy;
/**
* ProxyStar:模拟动态生成的代理的类
*
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class ProxyStar implements Star {
/**
* 注入代理处理器类(动态代理是代理类这句话,就是来自这里),在静态代理这里是直接注入的private Star star 接口,就是代理的是接口
* ---一句话代理类,这个类是动态的哈
*/
StarHandler handler;
/**
* 使用构造方法实现注入,set方法也行,不赘述
*
* @param handler
*/
public ProxyStar(StarHandler handler) {
this.handler = handler;
}
/**
* 面谈
*/
@Override
public void confer() {
// handler.invoke(this,当前方法 , args);
}
/**
* 签合同
*/
@Override
public void signContract() {
// handler.invoke(this,当前方法 , args);
}
/**
* 订票
*/
@Override
public void bookTicket() {
// handler.invoke(this,当前方法 , args);
}
/**
* 唱歌
*/
@Override
public void sing() {
// handler.invoke(this,当前方法 , args);
}
/**
* 收钱
*/
@Override
public void collectMoney() {
// handler.invoke(this,当前方法 , args);
}
}
客户端测试
package com.demo.proxy.dynamicproxy;
import java.lang.reflect.Proxy;
/**
* Client:客户端 测试动态代理
* @author zhangxiaoxiang
* @date 2019/8/9
*/
public class Client {
public static void main(String[] args) {
System.out.println("----------测试的动态代理-----------");
Star realStar = new RealStar();
//代理类
StarHandler handler = new StarHandler(realStar);
//利用JDK生成代理对象
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Star.class}, handler);
proxy.sing();
}
}
动态代理的演唱会事故现场
5 动态代理实现原理
解答一下main()方法工作流程:第1、2行代码分别是生成被代理对象和InvocationHandler,第3行代码生成代理对象,这里生成的proxy实际上是com.sun.proxy.$Proxy
类型,这个类是通过反射的方式动态生成的,它实现了Rent接口(后面解释),所以可以强制转换,另外$Proxy
内部的方法调用了Proxy类的invoke方法,以达到调用InvocationHandler 接口类的invoke()方法,我们在RentHouseHandler 对InvocationHandler实现了,所以就调用了RentHouseHandler的invoke()方法,这样就达到了代理的目的
(1)newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法三个参数:
loader: the class loader to define the proxy class 为了实现我们代理类而需要的ClassLoader,这个参数目前还不知道有什么限制,我试验其实是可以传入Main.class.getClassLoader()、RentInGZ.class.getClassLoader()、Rent.class.getClassLoader(),甚至是可以其他和这里不相干的类的ClassLoader
interfaces: 被代理类实现的接口,这个很好理解啦,你要代理什么类,就传入这个类实现的接口喽
h:就是实现了InvocationHandler的代理handler了
这三个参数在后面生成$Proxy
的时候会被使用到
2)上面第二第三个问题的解答
在解答上面问题之前,我们先看一下Proxy.newProxyInstance()的源码:
newProxyInstance()方法里面生成实例的关键代码是:
设为代码段A
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
* 这里生成我们的代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//这里使用Constructor.newInstance(h)的方法生成代理类的实例,h是构造器的参数
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
关键步骤就是两个,首先getProxyClass0(loader, intfs);
获取到Class对象,然后Class.getConstructor().newInstance()获取到实例,这样就返回了$Proxy
实例
好,进入内部看看getProxyClass0(loader, intfs);
方法:
设为代码段B
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
//省略前面的判断
return proxyClassCache.get(loader, interfaces);
}
设为代码段C
public V get(K key, P parameter) {
......
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
//调用的factory.get()
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
可以看到的是key就是ClassLoader,parameter就是interfaces,当调用supplier.get()的时候,实际上调用的是factory.get():
设为代码段D
public synchronized V get() { // serialize access
......
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
......
return value;
}
这里调用的是Proxy.ProxyClassFactory.apply方法:
设为代码段E
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//(1)--------------------------------------------
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//(2)----------------------------------------------------------------------
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
* 生成 报名+类似$Proxy0 之类的名字
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 这里生成字节码的$Proxy0
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
这个方法主要干了这2件事:(1)部分就是验证interfaces不要出现相同的类型导致冲突 (2)通过反射生成$Proxy
类
$Proxy
这个类是动态生成的,可以通过保存到文件查看:
public static void main(String[] args) {
Rent rentInGZ = new RentInGZ();
RentHouseHandler rhProxy = new RentHouseHandler(rentInGZ);
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
rhProxy.getClass().getName(), rentInGZ.getClass().getInterfaces());
try {
FileOutputStream out = new FileOutputStream("proxy.class");
out.write(proxyClassFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
然后反编译proxy.class文件,源代码如下:
设为代码段F
package pattern.com.helloAspect.self;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class RentHouseHandler extends Proxy implements Rent {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public RentHouseHandler(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String findHouse(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 void rentHouse() throws {
try {
super.h.invoke(this, m4, (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)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("pattern.com.helloAspect.self.Rent").getMethod("findHouse", new Class[]{Class.forName("java.lang.String")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("pattern.com.helloAspect.self.Rent").getMethod("rentHouse", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
这就是我们生成的$Proxy
类了,可以看到这个类实现了Rent接口,我们测试类中的rent实例,是$Proxy()
类型的,但是仍然可以强制转换为Rent
public static void main(String[] args) {
Rent rentInGZ = new RentInGZ();
RentHouseHandler rhProxy = new RentHouseHandler(rentInGZ);
Rent rent = (Rent) Proxy.newProxyInstance(rhProxy.getClass().getClassLoader(), new RentInGZ().getClass().getInterfaces(), rhProxy);
System.out.println(rent.getClass());//输出 class com.sun.proxy.$Proxy0
}
另外 我们可以看到,这个类的构造器是一个传入了InvocationHandler类型的参数的构造器,这就是为什么我们在Proxy.newInstanceProxy()传入InvocationHandler了,生成的源代码是对应“代码段A”的cons.newInstance(new Object[]{h});
这一段代码,前面已经解释了
还有,这个类实现Rent接口的方法的时候,是直接通过h.invoke(this, m, new Object[]{var1})实现的,这样就可以解释为什么代理类执行被代理对象的方法的时候,会调用InvocationHanlder里面的invoke()方法了,理所当然的,我们也知道了InvocationHandler的invoke()方法的三个参数分别表示:$Proxy,被代理对象传入的方法,被代理对象传入方法的参数
结论:
(1)通过反编译$Proxy
类我们可以知道,$Proxy
继承了Proxy, 由于Java不能多继承,所以动态代理只支持借口的代理
(2)$Proxy
里面有关equals、hansCode、toString方法也是调用的h.invoke(),所以也支持这三个方法的代理