美发技能:
public interface Hairdressing {
int haircut();
}
理发师:
public class Barber implements Hairdressing {
private String name;
public Barber(String name){
this.name = name;
}
@Override
public int haircut() {
System.out.println(name + "老师剪头");
return 50;
}
}
理发店(静态代理):
public class Barbershop implements Hairdressing {
private String barberName;
private Barber barber;
public Barbershop(String barberName){
this.barberName = barberName;
}
@Override
public int haircut() {
if (barber == null){
barber = new Barber(barberName);
System.out.println("先洗头");
barber.haircut();
System.out.println("再洗头");
}
return 50;
}
}
测试类:
public class ProxyTest {
public static void main(String[] args) {
//静态代理
Barbershop barbershop = new Barbershop("托尼");
int money = barbershop.haircut();
System.out.println("需要付:" + money + "元");
System.out.println("------------------------------------------");
//动态代理
Barber barber = new Barber("托尼");
Object proxyInstance = Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先洗头");
Object o = method.invoke(barber, args);
System.out.println("再洗头");
return o;
}
});
Hairdressing hairdressing = (Hairdressing) proxyInstance;
int money1 = hairdressing.haircut();
System.out.println("需要付:" + money1 + "元");
System.out.println("------------------------------------------");
System.out.println(hairdressing.toString());
}
}
执行结果
先介绍一下动态代理的使用:
Object proxyInstance = Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("先洗头");
Object o = method.invoke(barber, args);
System.out.println("再洗头");
return o;
}
});
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
三个参数:
第一个:classLoader随便给一个Classloader
第二个:一个数组里面是要代理的所有的接口Class
第三个:InvocationHandler 是一个接口,参数是接口
用法:
通过Proxy.newProxyInstance生成一个代理,代理可以强转成接口类型后,调用接口,当调用接口的时候就会触发InvocationHandler的invoke方法:
invoke(Object proxy, Method method, Object[] args)
三个参数:
第一个:动态代理的实例
第二个:反射Method,这个Method就是上面接口调用的方法的Method
第三个:是上面调用的接口的参数,在这里给Method用的
知道用法后,思考几个问题:
1.这个动态代理对象是什么,怎么得到的,为什么能强转成那些传入的Proxy.newProxyInstance中的第二个参数的接口
2.怎么实现的一调用我们传入Proxy.newProxyInstance中的第二个参数中接口中的方法,就会触发InvocationHandler的invoke方法,并且把调用的那个方法的Method和参数传过来。
带着这两个问题去看源码:
动态代理原理:
实际上, Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译
而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class,这个Class就是动态代理类我们反编译后:
public final class Proxy4 extends Proxy
implements Hairdressing
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public Proxy4(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return ((String)this.h.invoke(this, m2, null));
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public int haircut() {
throws
{
try
{
return ((Integer)this.h.invoke(this, m3,null));
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com/example/fragmentadaptertest/proxy/Hairdressing.java").getMethod("haircut", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
在此Class的clinit(静态代码块与静态属性组成的方法)中,获得 method 备用。
在生成动态代理的Class的时候在static代码块中,把Hairdressing接口中的方法都搞成了method
在上面的例子中就是:m1,m2,m3,m4
而这个代理类中所有方法的实现变为:
public int haircut() {
throws
{
try {
return ((Integer) this.h.invoke(this, m3, null));
} catch (RuntimeException localRuntimeException) {
throw localRuntimeException;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
}
首先看this.h是什么,this很明显就是我们的Proxy4的实例,可是Proxy4中没有h这个属性,那我们从父类Proxy中找:
果然父类中有,这个h就是我们调用
Proxy.newProxyInstance(Barber.class.getClassLoader(), Barber.class.getInterfaces(), new InvocationHandler(){})这个方法的第三个参数传进来的InvocationHandler的实例。
通过生成的动态代理类的这个haircut方法可以看到,动态代理每次调用接口中的方法,实际是调用的 this.h.invoke(this, Method method, Object[] args)),也就是我们的InvocationHandler中的ivoke方法。
下面简单看一下源码流程:
从这个Proxy.newProxyInstance看起:
只搞成主线流程:
看上面我们生成的代理类Proxy4的构造方法,是继承的Proxy的构造方法:
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
到这里就打通了,通过Proxy.newProxyInstance在内存中生成了一个动态代理的class,并且返回这个class的实例,这个class继承Proxy类,实现了我们传入的Proxy.newProxyInstance的第二个参数接口数组中的所有接口,把第三个参数就是我们的InvocationHandler的实例当作构造函数的参数传入Proxy中维护,在static静态代码块中把接口中所有的方法都搞成method获取到维护在类中备用,在代理类中重写了接口中所有的方法,这些重写的方法的实现都是this.h.invoke(this, Method method, Object[] args)),当动态代理的实例调用接口中的任何一个方法时,通过源码我们看到其实是调用了InvocationHandler的invoke方法。
为什么JDK的动态代理只能代理接口不能代理类
我们生成的代理类的Class源码:public final class Proxy4 extends Proxy implements Hairdressing。生成的代理类默认继承了Proxy这个类,而java中又是单继承的,所以只能代理接口,不能代理类。